summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/rendering
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/rendering')
-rw-r--r--Source/WebCore/rendering/AutoTableLayout.cpp52
-rw-r--r--Source/WebCore/rendering/CounterNode.cpp99
-rw-r--r--Source/WebCore/rendering/CounterNode.h25
-rw-r--r--Source/WebCore/rendering/FixedTableLayout.cpp16
-rw-r--r--Source/WebCore/rendering/HitTestResult.cpp39
-rw-r--r--Source/WebCore/rendering/HitTestResult.h12
-rw-r--r--Source/WebCore/rendering/InlineBox.cpp5
-rw-r--r--Source/WebCore/rendering/InlineBox.h9
-rw-r--r--Source/WebCore/rendering/InlineFlowBox.cpp398
-rw-r--r--Source/WebCore/rendering/InlineFlowBox.h20
-rw-r--r--Source/WebCore/rendering/InlineIterator.h173
-rw-r--r--Source/WebCore/rendering/InlineTextBox.cpp79
-rw-r--r--Source/WebCore/rendering/InlineTextBox.h10
-rw-r--r--Source/WebCore/rendering/MediaControlElements.cpp182
-rw-r--r--Source/WebCore/rendering/MediaControlElements.h53
-rw-r--r--Source/WebCore/rendering/RenderBlock.cpp292
-rw-r--r--Source/WebCore/rendering/RenderBlock.h55
-rw-r--r--Source/WebCore/rendering/RenderBlockLineLayout.cpp602
-rw-r--r--Source/WebCore/rendering/RenderBox.cpp166
-rw-r--r--Source/WebCore/rendering/RenderBox.h7
-rw-r--r--Source/WebCore/rendering/RenderBoxModelObject.cpp7
-rw-r--r--Source/WebCore/rendering/RenderCombineText.cpp11
-rw-r--r--Source/WebCore/rendering/RenderCombineText.h6
-rw-r--r--Source/WebCore/rendering/RenderCounter.cpp72
-rw-r--r--Source/WebCore/rendering/RenderCounter.h14
-rw-r--r--Source/WebCore/rendering/RenderDataGrid.cpp14
-rw-r--r--Source/WebCore/rendering/RenderDataGrid.h5
-rw-r--r--Source/WebCore/rendering/RenderDetails.cpp302
-rw-r--r--Source/WebCore/rendering/RenderDetails.h55
-rw-r--r--Source/WebCore/rendering/RenderDetailsMarker.cpp177
-rw-r--r--Source/WebCore/rendering/RenderDetailsMarker.h37
-rw-r--r--Source/WebCore/rendering/RenderFlexibleBox.cpp26
-rw-r--r--Source/WebCore/rendering/RenderFullScreen.cpp2
-rw-r--r--Source/WebCore/rendering/RenderInline.cpp21
-rw-r--r--Source/WebCore/rendering/RenderInline.h4
-rw-r--r--Source/WebCore/rendering/RenderLayer.cpp108
-rw-r--r--Source/WebCore/rendering/RenderLayer.h46
-rw-r--r--Source/WebCore/rendering/RenderLayerBacking.cpp63
-rw-r--r--Source/WebCore/rendering/RenderLayerBacking.h3
-rw-r--r--Source/WebCore/rendering/RenderLayerCompositor.cpp19
-rw-r--r--Source/WebCore/rendering/RenderLayerCompositor.h3
-rw-r--r--Source/WebCore/rendering/RenderListBox.cpp60
-rw-r--r--Source/WebCore/rendering/RenderListBox.h5
-rw-r--r--Source/WebCore/rendering/RenderMedia.cpp2
-rw-r--r--Source/WebCore/rendering/RenderMenuList.cpp1
-rw-r--r--Source/WebCore/rendering/RenderObject.cpp40
-rw-r--r--Source/WebCore/rendering/RenderObject.h59
-rw-r--r--Source/WebCore/rendering/RenderObjectChildList.cpp25
-rw-r--r--Source/WebCore/rendering/RenderObjectChildList.h1
-rw-r--r--Source/WebCore/rendering/RenderRubyRun.cpp6
-rw-r--r--Source/WebCore/rendering/RenderSlider.cpp2
-rw-r--r--Source/WebCore/rendering/RenderSummary.cpp36
-rw-r--r--Source/WebCore/rendering/RenderSummary.h9
-rw-r--r--Source/WebCore/rendering/RenderTable.cpp27
-rw-r--r--Source/WebCore/rendering/RenderTable.h2
-rw-r--r--Source/WebCore/rendering/RenderTableCell.cpp19
-rw-r--r--Source/WebCore/rendering/RenderTableCell.h9
-rw-r--r--Source/WebCore/rendering/RenderTableRow.cpp11
-rw-r--r--Source/WebCore/rendering/RenderTableRow.h1
-rw-r--r--Source/WebCore/rendering/RenderTableSection.cpp14
-rw-r--r--Source/WebCore/rendering/RenderText.cpp24
-rw-r--r--Source/WebCore/rendering/RenderText.h2
-rw-r--r--Source/WebCore/rendering/RenderTextControlSingleLine.cpp2
-rw-r--r--Source/WebCore/rendering/RenderTheme.cpp8
-rw-r--r--Source/WebCore/rendering/RenderTheme.h3
-rw-r--r--Source/WebCore/rendering/RenderThemeChromiumWin.cpp6
-rw-r--r--Source/WebCore/rendering/RenderThemeMac.h3
-rw-r--r--Source/WebCore/rendering/RenderThemeMac.mm27
-rw-r--r--Source/WebCore/rendering/RenderThemeWin.cpp14
-rw-r--r--Source/WebCore/rendering/RenderTreeAsText.cpp36
-rw-r--r--Source/WebCore/rendering/RenderVideo.cpp2
-rw-r--r--Source/WebCore/rendering/RenderWidget.cpp2
-rw-r--r--Source/WebCore/rendering/RootInlineBox.cpp282
-rw-r--r--Source/WebCore/rendering/RootInlineBox.h15
-rw-r--r--Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp5
-rw-r--r--Source/WebCore/rendering/style/BorderData.h8
-rw-r--r--Source/WebCore/rendering/style/FillLayer.cpp18
-rw-r--r--Source/WebCore/rendering/style/RenderStyle.cpp49
-rw-r--r--Source/WebCore/rendering/style/RenderStyle.h11
-rw-r--r--Source/WebCore/rendering/style/RenderStyleConstants.h5
-rw-r--r--Source/WebCore/rendering/style/StyleRareInheritedData.cpp3
-rw-r--r--Source/WebCore/rendering/style/StyleRareInheritedData.h1
-rw-r--r--Source/WebCore/rendering/style/StyleRareNonInheritedData.h2
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp1
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGText.cpp7
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGText.h8
-rw-r--r--Source/WebCore/rendering/svg/SVGInlineTextBox.cpp6
-rw-r--r--Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp6
-rw-r--r--Source/WebCore/rendering/svg/SVGRootInlineBox.cpp102
-rw-r--r--Source/WebCore/rendering/svg/SVGRootInlineBox.h1
-rw-r--r--Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp4
-rw-r--r--Source/WebCore/rendering/svg/SVGShadowTreeElements.h1
-rw-r--r--Source/WebCore/rendering/svg/SVGTextChunk.cpp24
-rw-r--r--Source/WebCore/rendering/svg/SVGTextChunk.h31
-rw-r--r--Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp46
-rw-r--r--Source/WebCore/rendering/svg/SVGTextFragment.h8
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp5
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h7
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp31
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h2
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp237
-rw-r--r--Source/WebCore/rendering/svg/SVGTextLayoutEngine.h19
-rw-r--r--Source/WebCore/rendering/svg/SVGTextMetrics.cpp28
-rw-r--r--Source/WebCore/rendering/svg/SVGTextMetrics.h5
-rw-r--r--Source/WebCore/rendering/svg/SVGTextQuery.cpp10
105 files changed, 3298 insertions, 1437 deletions
diff --git a/Source/WebCore/rendering/AutoTableLayout.cpp b/Source/WebCore/rendering/AutoTableLayout.cpp
index 9775ec5..4eef95f 100644
--- a/Source/WebCore/rendering/AutoTableLayout.cpp
+++ b/Source/WebCore/rendering/AutoTableLayout.cpp
@@ -81,8 +81,8 @@ void AutoTableLayout::recalcColumn(int effCol)
Length cellLogicalWidth = cell->styleOrColLogicalWidth();
// FIXME: What is this arbitrary value?
- if (cellLogicalWidth.rawValue() > 32760)
- cellLogicalWidth.setRawValue(32760);
+ if (cellLogicalWidth.value() > 32760)
+ cellLogicalWidth.setValue(32760);
if (cellLogicalWidth.isNegative())
cellLogicalWidth.setValue(0);
switch (cellLogicalWidth.type()) {
@@ -105,13 +105,13 @@ void AutoTableLayout::recalcColumn(int effCol)
break;
case Percent:
m_hasPercent = true;
- if (cellLogicalWidth.isPositive() && (!columnLayout.logicalWidth.isPercent() || cellLogicalWidth.rawValue() > columnLayout.logicalWidth.rawValue()))
+ if (cellLogicalWidth.isPositive() && (!columnLayout.logicalWidth.isPercent() || cellLogicalWidth.value() > columnLayout.logicalWidth.value()))
columnLayout.logicalWidth = cellLogicalWidth;
break;
case Relative:
// FIXME: Need to understand this case and whether it makes sense to compare values
// which are not necessarily of the same type.
- if (cellLogicalWidth.isAuto() || (cellLogicalWidth.isRelative() && cellLogicalWidth.value() > columnLayout.logicalWidth.rawValue()))
+ if (cellLogicalWidth.isAuto() || (cellLogicalWidth.isRelative() && cellLogicalWidth.value() > columnLayout.logicalWidth.value()))
columnLayout.logicalWidth = cellLogicalWidth;
default:
break;
@@ -232,16 +232,16 @@ void AutoTableLayout::computePreferredLogicalWidths(int& minWidth, int& maxWidth
// We substitute 0 percent by (epsilon / percentScaleFactor) percent in two places below to avoid division by zero.
// FIXME: Handle the 0% cases properly.
- const int epsilon = 1;
+ const float epsilon = 1 / 128.0f;
- int remainingPercent = 100 * percentScaleFactor;
+ float remainingPercent = 100;
for (size_t i = 0; i < m_layoutStruct.size(); ++i) {
minWidth += m_layoutStruct[i].effectiveMinLogicalWidth;
maxWidth += m_layoutStruct[i].effectiveMaxLogicalWidth;
if (scaleColumns) {
if (m_layoutStruct[i].effectiveLogicalWidth.isPercent()) {
- int percent = min(m_layoutStruct[i].effectiveLogicalWidth.rawValue(), remainingPercent);
- float logicalWidth = static_cast<float>(m_layoutStruct[i].effectiveMaxLogicalWidth) * 100 * percentScaleFactor / max(percent, epsilon);
+ float percent = min(static_cast<float>(m_layoutStruct[i].effectiveLogicalWidth.percent()), remainingPercent);
+ float logicalWidth = static_cast<float>(m_layoutStruct[i].effectiveMaxLogicalWidth) * 100 / max(percent, epsilon);
maxPercent = max(logicalWidth, maxPercent);
remainingPercent -= percent;
} else
@@ -250,7 +250,7 @@ void AutoTableLayout::computePreferredLogicalWidths(int& minWidth, int& maxWidth
}
if (scaleColumns) {
- maxNonPercent = maxNonPercent * 100 * percentScaleFactor / max(remainingPercent, epsilon);
+ maxNonPercent = maxNonPercent * 100 / max(remainingPercent, epsilon);
maxWidth = max(maxWidth, static_cast<int>(min(maxNonPercent, INT_MAX / 2.0f)));
maxWidth = max(maxWidth, static_cast<int>(min(maxPercent, INT_MAX / 2.0f)));
}
@@ -266,6 +266,10 @@ void AutoTableLayout::computePreferredLogicalWidths(int& minWidth, int& maxWidth
minWidth = max(minWidth, tableLogicalWidth.value());
maxWidth = minWidth;
}
+
+ // if there was no remaining percent, maxWidth is invalid.
+ if (!remainingPercent && maxNonPercent)
+ maxWidth = intMaxForLength;
}
/*
@@ -300,7 +304,7 @@ int AutoTableLayout::calcEffectiveLogicalWidth()
size_t lastCol = effCol;
int cellMinLogicalWidth = cell->minPreferredLogicalWidth() + spacingInRowDirection;
float cellMaxLogicalWidth = cell->maxPreferredLogicalWidth() + spacingInRowDirection;
- int totalPercent = 0;
+ float totalPercent = 0;
int spanMinLogicalWidth = 0;
float spanMaxLogicalWidth = 0;
bool allColsArePercent = true;
@@ -312,7 +316,7 @@ int AutoTableLayout::calcEffectiveLogicalWidth()
Layout& columnLayout = m_layoutStruct[lastCol];
switch (columnLayout.logicalWidth.type()) {
case Percent:
- totalPercent += columnLayout.logicalWidth.rawValue();
+ totalPercent += columnLayout.logicalWidth.percent();
allColsAreFixed = false;
break;
case Fixed:
@@ -339,7 +343,7 @@ int AutoTableLayout::calcEffectiveLogicalWidth()
columnLayout.effectiveLogicalWidth = Length();
allColsArePercent = false;
} else
- totalPercent += columnLayout.effectiveLogicalWidth.rawValue();
+ totalPercent += columnLayout.effectiveLogicalWidth.percent();
allColsAreFixed = false;
}
if (!columnLayout.emptyCellsOnly)
@@ -354,14 +358,14 @@ int AutoTableLayout::calcEffectiveLogicalWidth()
// adjust table max width if needed
if (cellLogicalWidth.isPercent()) {
- if (totalPercent > cellLogicalWidth.rawValue() || allColsArePercent) {
+ if (totalPercent > cellLogicalWidth.percent() || allColsArePercent) {
// can't satify this condition, treat as variable
cellLogicalWidth = Length();
} else {
- maxLogicalWidth = max(maxLogicalWidth, max(spanMaxLogicalWidth, cellMaxLogicalWidth) * 100 * percentScaleFactor / cellLogicalWidth.rawValue());
+ maxLogicalWidth = max(maxLogicalWidth, static_cast<float>(max(spanMaxLogicalWidth, cellMaxLogicalWidth) * 100 / cellLogicalWidth.percent()));
// all non percent columns in the span get percent values to sum up correctly.
- int percentMissing = cellLogicalWidth.rawValue() - totalPercent;
+ float percentMissing = cellLogicalWidth.percent() - totalPercent;
float totalWidth = 0;
for (unsigned pos = effCol; pos < lastCol; ++pos) {
if (!m_layoutStruct[pos].effectiveLogicalWidth.isPercent())
@@ -370,11 +374,11 @@ int AutoTableLayout::calcEffectiveLogicalWidth()
for (unsigned pos = effCol; pos < lastCol && totalWidth > 0; ++pos) {
if (!m_layoutStruct[pos].effectiveLogicalWidth.isPercent()) {
- int percent = static_cast<int>(percentMissing * static_cast<float>(m_layoutStruct[pos].effectiveMaxLogicalWidth) / totalWidth);
+ float percent = percentMissing * static_cast<float>(m_layoutStruct[pos].effectiveMaxLogicalWidth) / totalWidth;
totalWidth -= m_layoutStruct[pos].effectiveMaxLogicalWidth;
percentMissing -= percent;
if (percent > 0)
- m_layoutStruct[pos].effectiveLogicalWidth.setRawValue(Percent, percent);
+ m_layoutStruct[pos].effectiveLogicalWidth.setValue(Percent, percent);
else
m_layoutStruct[pos].effectiveLogicalWidth = Length();
}
@@ -495,7 +499,7 @@ void AutoTableLayout::layout()
int numFixed = 0;
float totalAuto = 0;
float totalFixed = 0;
- int totalPercent = 0;
+ float totalPercent = 0;
int allocAuto = 0;
unsigned numAutoEmptyCellsOnly = 0;
@@ -508,7 +512,7 @@ void AutoTableLayout::layout()
switch (logicalWidth.type()) {
case Percent:
havePercent = true;
- totalPercent += logicalWidth.rawValue();
+ totalPercent += logicalWidth.percent();
break;
case Relative:
totalRelative += logicalWidth.value();
@@ -542,9 +546,9 @@ void AutoTableLayout::layout()
m_layoutStruct[i].computedLogicalWidth = cellLogicalWidth;
}
}
- if (totalPercent > 100 * percentScaleFactor) {
+ if (totalPercent > 100) {
// remove overallocated space from the last columns
- int excess = tableLogicalWidth * (totalPercent - 100 * percentScaleFactor) / (100 * percentScaleFactor);
+ int excess = tableLogicalWidth * (totalPercent - 100) / 100;
for (int i = nEffCols - 1; i >= 0; --i) {
if (m_layoutStruct[i].effectiveLogicalWidth.isPercent()) {
int cellLogicalWidth = m_layoutStruct[i].computedLogicalWidth;
@@ -611,13 +615,13 @@ void AutoTableLayout::layout()
}
// spread over percent colums
- if (available > 0 && m_hasPercent && totalPercent < 100 * percentScaleFactor) {
+ if (available > 0 && m_hasPercent && totalPercent < 100) {
for (size_t i = 0; i < nEffCols; ++i) {
Length& logicalWidth = m_layoutStruct[i].effectiveLogicalWidth;
if (logicalWidth.isPercent()) {
- int cellLogicalWidth = available * logicalWidth.rawValue() / totalPercent;
+ int cellLogicalWidth = available * logicalWidth.percent() / totalPercent;
available -= cellLogicalWidth;
- totalPercent -= logicalWidth.rawValue();
+ totalPercent -= logicalWidth.percent();
m_layoutStruct[i].computedLogicalWidth += cellLogicalWidth;
if (!available || !totalPercent)
break;
diff --git a/Source/WebCore/rendering/CounterNode.cpp b/Source/WebCore/rendering/CounterNode.cpp
index eadd386..323f5db 100644
--- a/Source/WebCore/rendering/CounterNode.cpp
+++ b/Source/WebCore/rendering/CounterNode.cpp
@@ -32,7 +32,8 @@ CounterNode::CounterNode(RenderObject* o, bool hasResetType, int value)
: m_hasResetType(hasResetType)
, m_value(value)
, m_countInParent(0)
- , m_renderer(o)
+ , m_owner(o)
+ , m_rootRenderer(0)
, m_parent(0)
, m_previousSibling(0)
, m_nextSibling(0)
@@ -41,9 +42,14 @@ CounterNode::CounterNode(RenderObject* o, bool hasResetType, int value)
{
}
-PassRefPtr<CounterNode> CounterNode::create(RenderObject* renderer, bool hasResetType, int value)
+CounterNode::~CounterNode()
{
- return adoptRef(new CounterNode(renderer, hasResetType, value));
+ resetRenderers();
+}
+
+PassRefPtr<CounterNode> CounterNode::create(RenderObject* owner, bool hasResetType, int value)
+{
+ return adoptRef(new CounterNode(owner, hasResetType, value));
}
CounterNode* CounterNode::nextInPreOrderAfterChildren(const CounterNode* stayWithin) const
@@ -102,24 +108,76 @@ int CounterNode::computeCountInParent() const
return m_parent->m_value + increment;
}
-void CounterNode::resetRenderer(const AtomicString& identifier) const
+void CounterNode::addRenderer(RenderCounter* value)
+{
+ if (!value) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+ if (value->m_counterNode) {
+ ASSERT_NOT_REACHED();
+ value->m_counterNode->removeRenderer(value);
+ }
+ ASSERT(!value->m_nextForSameCounter);
+ for (RenderCounter* iterator = m_rootRenderer;iterator; iterator = iterator->m_nextForSameCounter) {
+ if (iterator == value) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+ }
+ value->m_nextForSameCounter = m_rootRenderer;
+ m_rootRenderer = value;
+ if (value->m_counterNode != this) {
+ if (value->m_counterNode) {
+ ASSERT_NOT_REACHED();
+ value->m_counterNode->removeRenderer(value);
+ }
+ value->m_counterNode = this;
+ }
+}
+
+void CounterNode::removeRenderer(RenderCounter* value)
{
- if (!m_renderer || m_renderer->documentBeingDestroyed())
+ if (!value) {
+ ASSERT_NOT_REACHED();
return;
- if (RenderObjectChildList* children = m_renderer->virtualChildren())
- children->invalidateCounters(m_renderer, identifier);
+ }
+ if (value->m_counterNode && value->m_counterNode != this) {
+ ASSERT_NOT_REACHED();
+ value->m_counterNode->removeRenderer(value);
+ }
+ RenderCounter* previous = 0;
+ for (RenderCounter* iterator = m_rootRenderer;iterator; iterator = iterator->m_nextForSameCounter) {
+ if (iterator == value) {
+ if (previous)
+ previous->m_nextForSameCounter = value->m_nextForSameCounter;
+ else
+ m_rootRenderer = value->m_nextForSameCounter;
+ value->m_nextForSameCounter = 0;
+ value->m_counterNode = 0;
+ return;
+ }
+ previous = iterator;
+ }
+ ASSERT_NOT_REACHED();
+}
+
+void CounterNode::resetRenderers()
+{
+ while (m_rootRenderer)
+ m_rootRenderer->invalidate(); // This makes m_rootRenderer point to the next renderer if any since it disconnects the m_rootRenderer from this.
}
-void CounterNode::resetRenderers(const AtomicString& identifier) const
+void CounterNode::resetThisAndDescendantsRenderers()
{
- const CounterNode* node = this;
+ CounterNode* node = this;
do {
- node->resetRenderer(identifier);
+ node->resetRenderers();
node = node->nextInPreOrder(this);
} while (node);
}
-void CounterNode::recount(const AtomicString& identifier)
+void CounterNode::recount()
{
for (CounterNode* node = this; node; node = node->m_nextSibling) {
int oldCount = node->m_countInParent;
@@ -127,7 +185,7 @@ void CounterNode::recount(const AtomicString& identifier)
if (oldCount == newCount)
break;
node->m_countInParent = newCount;
- node->resetRenderers(identifier);
+ node->resetThisAndDescendantsRenderers();
}
}
@@ -141,7 +199,7 @@ void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild, cons
if (newChild->m_hasResetType) {
while (m_lastChild != refChild)
- RenderCounter::destroyCounterNode(m_lastChild->renderer(), identifier);
+ RenderCounter::destroyCounterNode(m_lastChild->owner(), identifier);
}
CounterNode* next;
@@ -168,9 +226,9 @@ void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild, cons
}
newChild->m_countInParent = newChild->computeCountInParent();
- newChild->resetRenderers(identifier);
+ newChild->resetThisAndDescendantsRenderers();
if (next)
- next->recount(identifier);
+ next->recount();
return;
}
@@ -203,11 +261,11 @@ void CounterNode::insertAfter(CounterNode* newChild, CounterNode* refChild, cons
newChild->m_firstChild = 0;
newChild->m_lastChild = 0;
newChild->m_countInParent = newChild->computeCountInParent();
- newChild->resetRenderer(identifier);
- first->recount(identifier);
+ newChild->resetRenderers();
+ first->recount();
}
-void CounterNode::removeChild(CounterNode* oldChild, const AtomicString& identifier)
+void CounterNode::removeChild(CounterNode* oldChild)
{
ASSERT(oldChild);
ASSERT(!oldChild->m_firstChild);
@@ -235,7 +293,7 @@ void CounterNode::removeChild(CounterNode* oldChild, const AtomicString& identif
}
if (next)
- next->recount(identifier);
+ next->recount();
}
#ifndef NDEBUG
@@ -253,8 +311,9 @@ static void showTreeAndMark(const CounterNode* node)
fprintf(stderr, "%p %s: %d %d P:%p PS:%p NS:%p R:%p\n",
current, current->actsAsReset() ? "reset____" : "increment", current->value(),
current->countInParent(), current->parent(), current->previousSibling(),
- current->nextSibling(), current->renderer());
+ current->nextSibling(), current->owner());
}
+ fflush(stderr);
}
#endif
diff --git a/Source/WebCore/rendering/CounterNode.h b/Source/WebCore/rendering/CounterNode.h
index 639946c..7d6def8 100644
--- a/Source/WebCore/rendering/CounterNode.h
+++ b/Source/WebCore/rendering/CounterNode.h
@@ -38,16 +38,22 @@
namespace WebCore {
class RenderObject;
+class RenderCounter;
class CounterNode : public RefCounted<CounterNode> {
public:
static PassRefPtr<CounterNode> create(RenderObject*, bool isReset, int value);
-
+ ~CounterNode();
bool actsAsReset() const { return m_hasResetType || !m_parent; }
bool hasResetType() const { return m_hasResetType; }
int value() const { return m_value; }
int countInParent() const { return m_countInParent; }
- RenderObject* renderer() const { return m_renderer; }
+ RenderObject* owner() const { return m_owner; }
+ void addRenderer(RenderCounter*);
+ void removeRenderer(RenderCounter*);
+
+ // Invalidates the text in the renderers of this counter, if any.
+ void resetRenderers();
CounterNode* parent() const { return m_parent; }
CounterNode* previousSibling() const { return m_previousSibling; }
@@ -62,26 +68,21 @@ public:
void insertAfter(CounterNode* newChild, CounterNode* beforeChild, const AtomicString& identifier);
// identifier must match the identifier of this counter.
- void removeChild(CounterNode*, const AtomicString& identifier);
+ void removeChild(CounterNode*);
private:
CounterNode(RenderObject*, bool isReset, int value);
int computeCountInParent() const;
- void recount(const AtomicString& identifier);
-
- // Invalidates the text in the renderer of this counter, if any.
- // identifier must match the identifier of this counter.
- void resetRenderer(const AtomicString& identifier) const;
-
// Invalidates the text in the renderer of this counter, if any,
// and in the renderers of all descendants of this counter, if any.
- // identifier must match the identifier of this counter.
- void resetRenderers(const AtomicString& identifier) const;
+ void resetThisAndDescendantsRenderers();
+ void recount();
bool m_hasResetType;
int m_value;
int m_countInParent;
- RenderObject* m_renderer;
+ RenderObject* m_owner;
+ RenderCounter* m_rootRenderer;
CounterNode* m_parent;
CounterNode* m_previousSibling;
diff --git a/Source/WebCore/rendering/FixedTableLayout.cpp b/Source/WebCore/rendering/FixedTableLayout.cpp
index 3285d15..b1a61b5 100644
--- a/Source/WebCore/rendering/FixedTableLayout.cpp
+++ b/Source/WebCore/rendering/FixedTableLayout.cpp
@@ -118,7 +118,8 @@ int FixedTableLayout::calcWidthArray(int)
spanInCurrentEffectiveColumn = m_table->spanOfEffCol(currentEffectiveColumn);
}
if ((w.isFixed() || w.isPercent()) && w.isPositive()) {
- m_width[currentEffectiveColumn].setRawValue(w.type(), w.rawValue() * spanInCurrentEffectiveColumn);
+ m_width[currentEffectiveColumn] = w;
+ m_width[currentEffectiveColumn] *= spanInCurrentEffectiveColumn;
usedWidth += effWidth * spanInCurrentEffectiveColumn;
}
span -= spanInCurrentEffectiveColumn;
@@ -164,10 +165,11 @@ int FixedTableLayout::calcWidthArray(int)
int usedSpan = 0;
int i = 0;
while (usedSpan < span && cCol + i < nEffCols) {
- int eSpan = m_table->spanOfEffCol(cCol + i);
+ float eSpan = m_table->spanOfEffCol(cCol + i);
// Only set if no col element has already set it.
if (m_width[cCol + i].isAuto() && w.type() != Auto) {
- m_width[cCol + i].setRawValue(w.type(), w.rawValue() * eSpan / span);
+ m_width[cCol + i] = w;
+ m_width[cCol + i] *= eSpan / span;
usedWidth += effWidth * eSpan / span;
}
usedSpan += eSpan;
@@ -234,7 +236,7 @@ void FixedTableLayout::layout()
int autoSpan = 0;
int totalFixedWidth = 0;
int totalPercentWidth = 0;
- int totalRawPercent = 0;
+ float totalPercent = 0;
// Compute requirements and try to satisfy fixed and percent widths.
// Percentages are of the table's width, so for example
@@ -247,7 +249,7 @@ void FixedTableLayout::layout()
} else if (m_width[i].isPercent()) {
calcWidth[i] = m_width[i].calcValue(tableLogicalWidth);
totalPercentWidth += calcWidth[i];
- totalRawPercent += m_width[i].rawValue();
+ totalPercent += m_width[i].percent();
} else if (m_width[i].isAuto()) {
numAuto++;
autoSpan += m_table->spanOfEffCol(i);
@@ -270,11 +272,11 @@ void FixedTableLayout::layout()
}
}
}
- if (totalRawPercent) {
+ if (totalPercent) {
totalPercentWidth = 0;
for (int i = 0; i < nEffCols; i++) {
if (m_width[i].isPercent()) {
- calcWidth[i] = m_width[i].rawValue() * (tableLogicalWidth - totalFixedWidth) / totalRawPercent;
+ calcWidth[i] = m_width[i].percent() * (tableLogicalWidth - totalFixedWidth) / totalPercent;
totalPercentWidth += calcWidth[i];
}
}
diff --git a/Source/WebCore/rendering/HitTestResult.cpp b/Source/WebCore/rendering/HitTestResult.cpp
index ba98eff..e5638c9 100644
--- a/Source/WebCore/rendering/HitTestResult.cpp
+++ b/Source/WebCore/rendering/HitTestResult.cpp
@@ -95,16 +95,17 @@ HitTestResult::HitTestResult(const HitTestResult& other)
, m_scrollbar(other.scrollbar())
, m_isOverWidget(other.isOverWidget())
{
- // Only copy the padding and ListHashSet in case of rect hit test.
+ // Only copy the padding and NodeSet in case of rect hit test.
// Copying the later is rather expensive.
if ((m_isRectBased = other.isRectBasedTest())) {
m_topPadding = other.m_topPadding;
m_rightPadding = other.m_rightPadding;
m_bottomPadding = other.m_bottomPadding;
m_leftPadding = other.m_leftPadding;
- m_rectBasedTestResult = other.rectBasedTestResult();
} else
m_topPadding = m_rightPadding = m_bottomPadding = m_leftPadding = 0;
+
+ m_rectBasedTestResult = adoptPtr(other.m_rectBasedTestResult ? new NodeSet(*other.m_rectBasedTestResult) : 0);
}
HitTestResult::~HitTestResult()
@@ -120,16 +121,17 @@ HitTestResult& HitTestResult::operator=(const HitTestResult& other)
m_innerURLElement = other.URLElement();
m_scrollbar = other.scrollbar();
m_isOverWidget = other.isOverWidget();
- // Only copy the padding and ListHashSet in case of rect hit test.
+ // Only copy the padding and NodeSet in case of rect hit test.
// Copying the later is rather expensive.
if ((m_isRectBased = other.isRectBasedTest())) {
m_topPadding = other.m_topPadding;
m_rightPadding = other.m_rightPadding;
m_bottomPadding = other.m_bottomPadding;
m_leftPadding = other.m_leftPadding;
- m_rectBasedTestResult = other.rectBasedTestResult();
} else
m_topPadding = m_rightPadding = m_bottomPadding = m_leftPadding = 0;
+
+ m_rectBasedTestResult = adoptPtr(other.m_rectBasedTestResult ? new NodeSet(*other.m_rectBasedTestResult) : 0);
return *this;
}
@@ -525,7 +527,7 @@ bool HitTestResult::isContentEditable() const
if (m_innerNonSharedNode->hasTagName(inputTag))
return static_cast<HTMLInputElement*>(m_innerNonSharedNode.get())->isTextField();
- return m_innerNonSharedNode->isContentEditable();
+ return m_innerNonSharedNode->rendererIsEditable();
}
bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const IntRect& rect)
@@ -540,7 +542,7 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const
return true;
node = node->shadowAncestorNode();
- m_rectBasedTestResult.add(node);
+ mutableRectBasedTestResult().add(node);
return !rect.contains(rectForPoint(x, y));
}
@@ -557,7 +559,7 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, int x, int y, const
return true;
node = node->shadowAncestorNode();
- m_rectBasedTestResult.add(node);
+ mutableRectBasedTestResult().add(node);
return !rect.contains(rectForPoint(x, y));
}
@@ -575,10 +577,11 @@ void HitTestResult::append(const HitTestResult& other)
m_isOverWidget = other.isOverWidget();
}
- const ListHashSet<RefPtr<Node> >& list = other.rectBasedTestResult();
- ListHashSet<RefPtr<Node> >::const_iterator last = list.end();
- for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it)
- m_rectBasedTestResult.add(it->get());
+ if (other.m_rectBasedTestResult) {
+ NodeSet& set = mutableRectBasedTestResult();
+ for (NodeSet::const_iterator it = other.m_rectBasedTestResult->begin(), last = other.m_rectBasedTestResult->end(); it != last; ++it)
+ set.add(it->get());
+ }
}
IntRect HitTestResult::rectForPoint(const IntPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
@@ -593,4 +596,18 @@ IntRect HitTestResult::rectForPoint(const IntPoint& point, unsigned topPadding,
return IntRect(actualPoint, actualPadding);
}
+const HitTestResult::NodeSet& HitTestResult::rectBasedTestResult() const
+{
+ if (!m_rectBasedTestResult)
+ m_rectBasedTestResult = adoptPtr(new NodeSet);
+ return *m_rectBasedTestResult;
+}
+
+HitTestResult::NodeSet& HitTestResult::mutableRectBasedTestResult()
+{
+ if (!m_rectBasedTestResult)
+ m_rectBasedTestResult = adoptPtr(new NodeSet);
+ return *m_rectBasedTestResult;
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/rendering/HitTestResult.h b/Source/WebCore/rendering/HitTestResult.h
index 3aa17e3..89b5ea1 100644
--- a/Source/WebCore/rendering/HitTestResult.h
+++ b/Source/WebCore/rendering/HitTestResult.h
@@ -27,6 +27,7 @@
#include "TextDirection.h"
#include <wtf/Forward.h>
#include <wtf/ListHashSet.h>
+#include <wtf/OwnPtr.h>
#include <wtf/RefPtr.h>
namespace WebCore {
@@ -44,6 +45,8 @@ class Scrollbar;
class HitTestResult {
public:
+ typedef ListHashSet<RefPtr<Node> > NodeSet;
+
HitTestResult();
HitTestResult(const IntPoint&);
// Pass non-negative padding values to perform a rect-based hit test.
@@ -112,10 +115,15 @@ public:
// enclosed by the boundaries of a node.
bool addNodeToRectBasedTestResult(Node*, int x, int y, const IntRect& = IntRect());
bool addNodeToRectBasedTestResult(Node*, int x, int y, const FloatRect&);
- const ListHashSet<RefPtr<Node> >& rectBasedTestResult() const { return m_rectBasedTestResult; }
void append(const HitTestResult&);
+ // If m_rectBasedTestResult is 0 then set it to a new NodeSet. Return *m_rectBasedTestResult. Lazy allocation makes
+ // sense because the NodeSet is seldom necessary, and it's somewhat expensive to allocate and initialize. This method does
+ // the same thing as mutableRectBasedTestResult(), but here the return value is const.
+ const NodeSet& rectBasedTestResult() const;
+
private:
+ NodeSet& mutableRectBasedTestResult(); // See above.
#if ENABLE(VIDEO)
HTMLMediaElement* mediaElement() const;
@@ -134,7 +142,7 @@ private:
int m_rightPadding;
int m_bottomPadding;
int m_leftPadding;
- ListHashSet<RefPtr<Node> > m_rectBasedTestResult;
+ mutable OwnPtr<NodeSet> m_rectBasedTestResult;
};
inline IntRect HitTestResult::rectForPoint(int x, int y) const
diff --git a/Source/WebCore/rendering/InlineBox.cpp b/Source/WebCore/rendering/InlineBox.cpp
index 1f4e244..930071e 100644
--- a/Source/WebCore/rendering/InlineBox.cpp
+++ b/Source/WebCore/rendering/InlineBox.cpp
@@ -154,8 +154,9 @@ void InlineBox::adjustPosition(float dx, float dy)
{
m_x += dx;
m_y += dy;
- if (m_renderer->isReplaced())
- toRenderBox(m_renderer)->positionLineBox(this);
+
+ if (m_renderer->isReplaced())
+ toRenderBox(m_renderer)->move(dx, dy);
}
void InlineBox::paint(PaintInfo& paintInfo, int tx, int ty)
diff --git a/Source/WebCore/rendering/InlineBox.h b/Source/WebCore/rendering/InlineBox.h
index de7b224..9335970 100644
--- a/Source/WebCore/rendering/InlineBox.h
+++ b/Source/WebCore/rendering/InlineBox.h
@@ -53,7 +53,7 @@ public:
#endif
, m_isHorizontal(true)
, m_endsWithBreak(false)
- , m_hasSelectedChildren(false)
+ , m_hasSelectedChildrenOrCanHaveLeadingExpansion(false)
, m_hasEllipsisBoxOrHyphen(false)
, m_dirOverride(false)
, m_isText(false)
@@ -87,7 +87,7 @@ public:
#endif
, m_isHorizontal(isHorizontal)
, m_endsWithBreak(false)
- , m_hasSelectedChildren(false)
+ , m_hasSelectedChildrenOrCanHaveLeadingExpansion(false)
, m_hasEllipsisBoxOrHyphen(false)
, m_dirOverride(false)
, m_isText(false)
@@ -340,8 +340,9 @@ protected:
// for RootInlineBox
bool m_endsWithBreak : 1; // Whether the line ends with a <br>.
- bool m_hasSelectedChildren : 1; // Whether we have any children selected (this bit will also be set if the <br> that terminates our line is selected).
- bool m_hasEllipsisBoxOrHyphen : 1;
+ // shared between RootInlineBox and InlineTextBox
+ bool m_hasSelectedChildrenOrCanHaveLeadingExpansion : 1; // Whether we have any children selected (this bit will also be set if the <br> that terminates our line is selected).
+ bool m_hasEllipsisBoxOrHyphen : 1;
// for InlineTextBox
public:
diff --git a/Source/WebCore/rendering/InlineFlowBox.cpp b/Source/WebCore/rendering/InlineFlowBox.cpp
index e146dd9..b58a30e 100644
--- a/Source/WebCore/rendering/InlineFlowBox.cpp
+++ b/Source/WebCore/rendering/InlineFlowBox.cpp
@@ -38,7 +38,6 @@
#include "RenderTableCell.h"
#include "RootInlineBox.h"
#include "Text.h"
-#include "VerticalPositionCache.h"
#include <math.h>
@@ -97,8 +96,48 @@ void InlineFlowBox::addToLine(InlineBox* child)
}
child->setFirstLineStyleBit(m_firstLine);
child->setIsHorizontal(isHorizontal());
- if (child->isText())
+ if (child->isText()) {
m_hasTextChildren = true;
+ m_hasTextDescendants = true;
+ } else if (child->isInlineFlowBox()) {
+ if (static_cast<InlineFlowBox*>(child)->hasTextDescendants())
+ m_hasTextDescendants = true;
+ }
+
+ if (descendantsHaveSameLineHeightAndBaseline() && !child->renderer()->isPositioned()) {
+ RenderStyle* parentStyle = renderer()->style(m_firstLine);
+ RenderStyle* childStyle = child->renderer()->style(m_firstLine);
+ bool shouldClearDescendantsHaveSameLineHeightAndBaseline = false;
+ if (child->renderer()->isReplaced())
+ shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
+ else if (child->isText()) {
+ if (child->renderer()->isBR()) {
+ if (parentStyle->font().fontMetrics().ascent() != childStyle->font().fontMetrics().ascent()
+ || parentStyle->font().fontMetrics().descent() != childStyle->font().fontMetrics().descent() || parentStyle->lineHeight() != childStyle->lineHeight()
+ || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE)
+ shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
+ } else if (childStyle->hasTextCombine() || childStyle->textEmphasisMark() != TextEmphasisMarkNone)
+ shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
+ } else {
+ if (child->renderer()->isBR()) {
+ // FIXME: This is dumb. We only turn off because current layout test results expect the <br> to be 0-height on the baseline.
+ // Other than making a zillion tests have to regenerate results, there's no reason to ditch the optimization here.
+ shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
+ } else {
+ ASSERT(isInlineFlowBox());
+ InlineFlowBox* childFlowBox = static_cast<InlineFlowBox*>(child);
+ // Check the child's bit, and then also check for differences in font, line-height, vertical-align
+ if (!childFlowBox->descendantsHaveSameLineHeightAndBaseline() || parentStyle->font().fontMetrics().ascent() != childStyle->font().fontMetrics().ascent()
+ || parentStyle->font().fontMetrics().descent() != childStyle->font().fontMetrics().descent() || parentStyle->lineHeight() != childStyle->lineHeight()
+ || (parentStyle->verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle->verticalAlign() != BASELINE
+ || childStyle->hasBorder() || childStyle->hasPadding() || childStyle->hasTextCombine())
+ shouldClearDescendantsHaveSameLineHeightAndBaseline = true;
+ }
+ }
+
+ if (shouldClearDescendantsHaveSameLineHeightAndBaseline)
+ clearDescendantsHaveSameLineHeightAndBaseline();
+ }
checkConsistency();
}
@@ -214,7 +253,18 @@ bool InlineFlowBox::onEndChain(RenderObject* endObject)
return true;
}
-void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject)
+static bool isAnsectorAndWithinBlock(RenderObject* ancestor, RenderObject* child)
+{
+ RenderObject* object = child;
+ while (object && !object->isRenderBlock()) {
+ if (object == ancestor)
+ return true;
+ object = object->parent();
+ }
+ return false;
+}
+
+void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject, RenderObject* logicallyLastRunRenderer)
{
// All boxes start off open. They will not apply any margins/border/padding on
// any side.
@@ -234,23 +284,18 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en
else if (!ltr && lineBoxList->lastLineBox() == this)
includeRightEdge = true;
}
-
- // In order to determine if the inline ends on this line, we check three things:
- // (1) If we are the last line and we don't have a continuation(), then we can
- // close up.
- // (2) If the last line box for the flow has an object following it on the line (ltr,
- // reverse for rtl), then the inline has closed.
- // (3) The line may end on the inline. If we are the last child (climbing up
- // the end object's chain), then we just closed as well.
+
if (!lineBoxList->lastLineBox()->isConstructed()) {
RenderInline* inlineFlow = toRenderInline(renderer());
+ bool isLastObjectOnLine = (endObject && endObject->isText()) ? !isAnsectorAndWithinBlock(renderer(), logicallyLastRunRenderer->parent()) : onEndChain(logicallyLastRunRenderer);
+
if (ltr) {
- if (!nextLineBox() &&
- ((lastLine && !inlineFlow->continuation()) || nextOnLineExists() || onEndChain(endObject)))
+ if (!nextLineBox()
+ && ((lastLine || isLastObjectOnLine) && !inlineFlow->continuation()))
includeRightEdge = true;
} else {
- if ((!prevLineBox() || prevLineBox()->isConstructed()) &&
- ((lastLine && !inlineFlow->continuation()) || prevOnLineExists() || onEndChain(endObject)))
+ if ((!prevLineBox() || prevLineBox()->isConstructed())
+ && ((lastLine || isLastObjectOnLine) && !inlineFlow->continuation()))
includeLeftEdge = true;
}
}
@@ -262,7 +307,7 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en
for (InlineBox* currChild = firstChild(); currChild; currChild = currChild->nextOnLine()) {
if (currChild->isInlineFlowBox()) {
InlineFlowBox* currFlow = static_cast<InlineFlowBox*>(currChild);
- currFlow->determineSpacingForFlowBoxes(lastLine, endObject);
+ currFlow->determineSpacingForFlowBoxes(lastLine, endObject, logicallyLastRunRenderer);
}
}
}
@@ -325,7 +370,8 @@ bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFo
if (isHorizontal())
return false;
- if (renderer()->style(m_firstLine)->font().primaryFont()->orientation() == Vertical)
+ if (renderer()->style(m_firstLine)->fontDescription().textOrientation() == TextOrientationUpright
+ || renderer()->style(m_firstLine)->font().primaryFont()->hasVerticalGlyphs())
return true;
for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
@@ -336,7 +382,7 @@ bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFo
if (static_cast<InlineFlowBox*>(curr)->requiresIdeographicBaseline(textBoxDataMap))
return true;
} else {
- if (curr->renderer()->style(m_firstLine)->font().primaryFont()->orientation() == Vertical)
+ if (curr->renderer()->style(m_firstLine)->font().primaryFont()->hasVerticalGlyphs())
return true;
const Vector<const SimpleFontData*>* usedFonts = 0;
@@ -347,7 +393,7 @@ bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFo
if (usedFonts) {
for (size_t i = 0; i < usedFonts->size(); ++i) {
- if (usedFonts->at(i)->orientation() == Vertical)
+ if (usedFonts->at(i)->hasVerticalGlyphs())
return true;
}
}
@@ -384,92 +430,36 @@ void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, i
}
}
-static int verticalPositionForBox(InlineBox* box, FontBaseline baselineType, bool firstLine, VerticalPositionCache& verticalPositionCache)
-{
- if (box->renderer()->isText())
- return box->parent()->logicalTop();
-
- RenderBoxModelObject* renderer = box->boxModelObject();
- ASSERT(renderer->isInline());
- if (!renderer->isInline())
- return 0;
-
- // This method determines the vertical position for inline elements.
- if (firstLine && !renderer->document()->usesFirstLineRules())
- firstLine = false;
-
- // Check the cache.
- bool isRenderInline = renderer->isRenderInline();
- if (isRenderInline && !firstLine) {
- int verticalPosition = verticalPositionCache.get(renderer, baselineType);
- if (verticalPosition != PositionUndefined)
- return verticalPosition;
- }
-
- int verticalPosition = 0;
- EVerticalAlign verticalAlign = renderer->style()->verticalAlign();
- if (verticalAlign == TOP || verticalAlign == BOTTOM)
- return 0;
-
- RenderObject* parent = renderer->parent();
- if (parent->isRenderInline() && parent->style()->verticalAlign() != TOP && parent->style()->verticalAlign() != BOTTOM)
- verticalPosition = box->parent()->logicalTop();
-
- if (verticalAlign != BASELINE) {
- const Font& font = parent->style(firstLine)->font();
- const FontMetrics& fontMetrics = font.fontMetrics();
- int fontSize = font.pixelSize();
-
- LineDirectionMode lineDirection = parent->style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
-
- if (verticalAlign == SUB)
- verticalPosition += fontSize / 5 + 1;
- else if (verticalAlign == SUPER)
- verticalPosition -= fontSize / 3 + 1;
- else if (verticalAlign == TEXT_TOP)
- verticalPosition += renderer->baselinePosition(baselineType, firstLine, lineDirection) - fontMetrics.ascent(baselineType);
- else if (verticalAlign == MIDDLE)
- verticalPosition += -static_cast<int>(fontMetrics.xHeight() / 2) - renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType, firstLine, lineDirection);
- else if (verticalAlign == TEXT_BOTTOM) {
- verticalPosition += fontMetrics.descent(baselineType);
- // lineHeight - baselinePosition is always 0 for replaced elements (except inline blocks), so don't bother wasting time in that case.
- if (!renderer->isReplaced() || renderer->isInlineBlockOrInlineTable())
- verticalPosition -= (renderer->lineHeight(firstLine, lineDirection) - renderer->baselinePosition(baselineType, firstLine, lineDirection));
- } else if (verticalAlign == BASELINE_MIDDLE)
- verticalPosition += -renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType, firstLine, lineDirection);
- else if (verticalAlign == LENGTH)
- verticalPosition -= renderer->style()->verticalAlignLength().calcValue(renderer->lineHeight(firstLine, lineDirection));
- }
-
- // Store the cached value.
- if (isRenderInline && !firstLine)
- verticalPositionCache.set(renderer, baselineType, verticalPosition);
-
- return verticalPosition;
-}
-
-void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom,
+void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, int& maxPositionTop, int& maxPositionBottom,
int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent,
bool strictMode, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
FontBaseline baselineType, VerticalPositionCache& verticalPositionCache)
{
// The primary purpose of this function is to compute the maximal ascent and descent values for
- // a line.
+ // a line. These values are computed based off the block's line-box-contain property, which indicates
+ // what parts of descendant boxes have to fit within the line.
+ //
+ // The maxAscent value represents the distance of the highest point of any box (typically including line-height) from
+ // the root box's baseline. The maxDescent value represents the distance of the lowest point of any box
+ // (also typically including line-height) from the root box baseline. These values can be negative.
//
- // The maxAscent value represents the distance of the highest point of any box (including line-height) from
- // the root box's baseline. The maxDescent value represents the distance of the lowest point of any box
- // (also including line-height) from the root box baseline. These values can be negative.
+ // A secondary purpose of this function is to store the offset of every box's baseline from the root box's
+ // baseline. This information is cached in the logicalTop() of every box. We're effectively just using
+ // the logicalTop() as scratch space.
//
- // A secondary purpose of this function is to store the offset of very box's baseline from the root box's
- // baseline. This information is cached in the logicalTop() of every box. We're effectively just using
- // the logicalTop() as scratch space.
+ // Because a box can be positioned such that it ends up fully above or fully below the
+ // root line box, we only consider it to affect the maxAscent and maxDescent values if some
+ // part of the box (EXCLUDING leading) is above (for ascent) or below (for descent) the root box's baseline.
+ bool affectsAscent = false;
+ bool affectsDescent = false;
+ bool checkChildren = !descendantsHaveSameLineHeightAndBaseline();
+
if (isRootInlineBox()) {
// Examine our root box.
- int height = lineHeight();
- int baseline = baselinePosition(baselineType);
- if (hasTextChildren() || strictMode) {
- int ascent = baseline;
- int descent = height - ascent;
+ int ascent = 0;
+ int descent = 0;
+ rootBox->ascentAndDescentForBox(rootBox, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent);
+ if (strictMode || hasTextChildren() || (!checkChildren && hasTextDescendants())) {
if (maxAscent < ascent || !setMaxAscent) {
maxAscent = ascent;
setMaxAscent = true;
@@ -481,131 +471,96 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi
}
}
+ if (!checkChildren)
+ return;
+
for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
if (curr->renderer()->isPositioned())
continue; // Positioned placeholders don't affect calculations.
- bool isInlineFlow = curr->isInlineFlowBox();
+ InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? static_cast<InlineFlowBox*>(curr) : 0;
- // Because a box can be positioned such that it ends up fully above or fully below the
- // root line box, we only consider it to affect the maxAscent and maxDescent values if some
- // part of the box (EXCLUDING line-height) is above (for ascent) or below (for descent) the root box's baseline.
bool affectsAscent = false;
bool affectsDescent = false;
// The verticalPositionForBox function returns the distance between the child box's baseline
// and the root box's baseline. The value is negative if the child box's baseline is above the
// root box's baseline, and it is positive if the child box's baseline is below the root box's baseline.
- curr->setLogicalTop(verticalPositionForBox(curr, baselineType, m_firstLine, verticalPositionCache));
+ curr->setLogicalTop(rootBox->verticalPositionForBox(curr, verticalPositionCache));
- int lineHeight;
- int baseline;
- Vector<const SimpleFontData*>* usedFonts = 0;
- if (curr->isInlineTextBox()) {
- GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(static_cast<InlineTextBox*>(curr));
- usedFonts = it == textBoxDataMap.end() ? 0 : &it->second.first;
- }
-
- if (usedFonts && !usedFonts->isEmpty() && curr->renderer()->style(m_firstLine)->lineHeight().isNegative()) {
- usedFonts->append(curr->renderer()->style(m_firstLine)->font().primaryFont());
- bool baselineSet = false;
- baseline = 0;
- int baselineToBottom = 0;
- for (size_t i = 0; i < usedFonts->size(); ++i) {
- const FontMetrics& fontMetrics = usedFonts->at(i)->fontMetrics();
- int halfLeading = (fontMetrics.lineSpacing() - fontMetrics.height()) / 2;
- int usedFontBaseline = halfLeading + fontMetrics.ascent(baselineType);
- int usedFontBaselineToBottom = fontMetrics.lineSpacing() - usedFontBaseline;
- if (!baselineSet) {
- baselineSet = true;
- baseline = usedFontBaseline;
- baselineToBottom = usedFontBaselineToBottom;
- } else {
- baseline = max(baseline, usedFontBaseline);
- baselineToBottom = max(baselineToBottom, usedFontBaselineToBottom);
- }
- if (!affectsAscent)
- affectsAscent = fontMetrics.ascent() - curr->logicalTop() > 0;
- if (!affectsDescent)
- affectsDescent = fontMetrics.descent() + curr->logicalTop() > 0;
- }
- lineHeight = baseline + baselineToBottom;
- } else {
- lineHeight = curr->lineHeight();
- baseline = curr->baselinePosition(baselineType);
- if (curr->isText() || isInlineFlow) {
- // Examine the font box for inline flows and text boxes to see if any part of it is above the baseline.
- // If the top of our font box relative to the root box baseline is above the root box baseline, then
- // we are contributing to the maxAscent value.
- const FontMetrics& fontMetrics = curr->renderer()->style(m_firstLine)->fontMetrics();
- affectsAscent = fontMetrics.ascent(baselineType) - curr->logicalTop() > 0;
-
- // Descent is similar. If any part of our font box is below the root box's baseline, then
- // we contribute to the maxDescent value.
- affectsDescent = fontMetrics.descent(baselineType) + curr->logicalTop() > 0;
- } else {
- // Replaced elements always affect both the ascent and descent.
- affectsAscent = true;
- affectsDescent = true;
- }
- }
+ int ascent = 0;
+ int descent = 0;
+ rootBox->ascentAndDescentForBox(curr, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent);
+ int boxHeight = ascent + descent;
if (curr->verticalAlign() == TOP) {
- if (maxPositionTop < lineHeight)
- maxPositionTop = lineHeight;
+ if (maxPositionTop < ascent)
+ maxPositionTop = boxHeight;
} else if (curr->verticalAlign() == BOTTOM) {
- if (maxPositionBottom < lineHeight)
- maxPositionBottom = lineHeight;
- } else if ((!isInlineFlow || static_cast<InlineFlowBox*>(curr)->hasTextChildren()) || curr->boxModelObject()->hasInlineDirectionBordersOrPadding() || strictMode) {
+ if (maxPositionBottom < boxHeight)
+ maxPositionBottom = boxHeight;
+ } else if (!inlineFlowBox || strictMode || inlineFlowBox->hasTextChildren() || (inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants())
+ || inlineFlowBox->boxModelObject()->hasInlineDirectionBordersOrPadding()) {
// Note that these values can be negative. Even though we only affect the maxAscent and maxDescent values
// if our box (excluding line-height) was above (for ascent) or below (for descent) the root baseline, once you factor in line-height
// the final box can end up being fully above or fully below the root box's baseline! This is ok, but what it
// means is that ascent and descent (including leading), can end up being negative. The setMaxAscent and
// setMaxDescent booleans are used to ensure that we're willing to initially set maxAscent/Descent to negative
// values.
- int ascent = baseline - curr->logicalTop();
- int descent = lineHeight - ascent;
+ ascent -= curr->logicalTop();
+ descent += curr->logicalTop();
if (affectsAscent && (maxAscent < ascent || !setMaxAscent)) {
maxAscent = ascent;
setMaxAscent = true;
}
+
if (affectsDescent && (maxDescent < descent || !setMaxDescent)) {
maxDescent = descent;
setMaxDescent = true;
}
}
- if (curr->isInlineFlowBox())
- static_cast<InlineFlowBox*>(curr)->computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent,
- setMaxAscent, setMaxDescent, strictMode, textBoxDataMap,
- baselineType, verticalPositionCache);
+ if (inlineFlowBox)
+ inlineFlowBox->computeLogicalBoxHeights(rootBox, maxPositionTop, maxPositionBottom, maxAscent, maxDescent,
+ setMaxAscent, setMaxDescent, strictMode, textBoxDataMap,
+ baselineType, verticalPositionCache);
}
}
void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom, bool& setLineTop,
int& lineTopIncludingMargins, int& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline baselineType)
{
- if (isRootInlineBox())
- setLogicalTop(top + maxAscent - baselinePosition(baselineType)); // Place our root box.
+ bool isRootBox = isRootInlineBox();
+ if (isRootBox) {
+ const FontMetrics& fontMetrics = renderer()->style(m_firstLine)->fontMetrics();
+ setLogicalTop(top + maxAscent - fontMetrics.ascent(baselineType));
+ }
+
+ int adjustmentForChildrenWithSameLineHeightAndBaseline = 0;
+ if (descendantsHaveSameLineHeightAndBaseline()) {
+ adjustmentForChildrenWithSameLineHeightAndBaseline = logicalTop();
+ if (parent())
+ adjustmentForChildrenWithSameLineHeightAndBaseline += (boxModelObject()->borderBefore() + boxModelObject()->paddingBefore());
+ }
for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) {
if (curr->renderer()->isPositioned())
continue; // Positioned placeholders don't affect calculations.
-
- // Adjust boxes to use their real box y/height and not the logical height (as dictated by
- // line-height).
- bool isInlineFlow = curr->isInlineFlowBox();
- if (isInlineFlow)
- static_cast<InlineFlowBox*>(curr)->placeBoxesInBlockDirection(top, maxHeight, maxAscent, strictMode, lineTop, lineBottom, setLineTop,
- lineTopIncludingMargins, lineBottomIncludingMargins, hasAnnotationsBefore, hasAnnotationsAfter, baselineType);
+ if (descendantsHaveSameLineHeightAndBaseline()) {
+ curr->adjustBlockDirectionPosition(adjustmentForChildrenWithSameLineHeightAndBaseline);
+ continue;
+ }
+
+ InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? static_cast<InlineFlowBox*>(curr) : 0;
bool childAffectsTopBottomPos = true;
if (curr->verticalAlign() == TOP)
curr->setLogicalTop(top);
else if (curr->verticalAlign() == BOTTOM)
curr->setLogicalTop(top + maxHeight - curr->lineHeight());
else {
- if ((isInlineFlow && !static_cast<InlineFlowBox*>(curr)->hasTextChildren()) && !curr->boxModelObject()->hasInlineDirectionBordersOrPadding() && !strictMode)
+ if (!strictMode && inlineFlowBox && !inlineFlowBox->hasTextChildren() && !curr->boxModelObject()->hasInlineDirectionBordersOrPadding()
+ && !(inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants()))
childAffectsTopBottomPos = false;
int posAdjust = maxAscent - curr->baselinePosition(baselineType);
curr->setLogicalTop(curr->logicalTop() + top + posAdjust);
@@ -676,13 +631,16 @@ void InlineFlowBox::placeBoxesInBlockDirection(int top, int maxHeight, int maxAs
lineBottom = max(lineBottom, newLogicalTop + boxHeight);
lineBottomIncludingMargins = max(lineBottom, max(lineBottomIncludingMargins, newLogicalTopIncludingMargins + boxHeightIncludingMargins));
}
+
+ // Adjust boxes to use their real box y/height and not the logical height (as dictated by
+ // line-height).
+ if (inlineFlowBox)
+ inlineFlowBox->placeBoxesInBlockDirection(top, maxHeight, maxAscent, strictMode, lineTop, lineBottom, setLineTop,
+ lineTopIncludingMargins, lineBottomIncludingMargins, hasAnnotationsBefore, hasAnnotationsAfter, baselineType);
}
- if (isRootInlineBox()) {
- const FontMetrics& fontMetrics = renderer()->style(m_firstLine)->fontMetrics();
- setLogicalTop(logicalTop() + baselinePosition(baselineType) - fontMetrics.ascent(baselineType));
-
- if (hasTextChildren() || strictMode) {
+ if (isRootBox) {
+ if (strictMode || hasTextChildren() || (descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
if (!setLineTop) {
setLineTop = true;
lineTop = logicalTop();
@@ -919,10 +877,29 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
}
}
- // Now check ourselves.
- FloatPoint boxOrigin = locationIncludingFlipping();
- boxOrigin.move(tx, ty);
- FloatRect rect(boxOrigin, IntSize(width(), height()));
+ // Now check ourselves. Pixel snap hit testing.
+ IntRect frameRect = roundedFrameRect();
+ int minX = frameRect.x();
+ int minY = frameRect.y();
+ int width = frameRect.width();
+ int height = frameRect.height();
+
+ // Constrain our hit testing to the line top and bottom if necessary.
+ bool noQuirksMode = renderer()->document()->inNoQuirksMode();
+ if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
+ RootInlineBox* rootBox = root();
+ int& top = isHorizontal() ? minY : minX;
+ int& logicalHeight = isHorizontal() ? height : width;
+ int bottom = min(rootBox->lineBottom(), top + logicalHeight);
+ top = max(rootBox->lineTop(), top);
+ logicalHeight = bottom - top;
+ }
+
+ // Move x/y to our coordinates.
+ IntRect rect(minX, minY, width, height);
+ flipForWritingMode(rect);
+ rect.move(tx, ty);
+
if (visibleToHitTesting() && rect.intersects(result.rectForPoint(x, y))) {
renderer()->updateHitTestResult(result, flipForWritingMode(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))
@@ -1074,7 +1051,7 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
// Constrain our background/border painting to the line top and bottom if necessary.
bool noQuirksMode = renderer()->document()->inNoQuirksMode();
- if (!hasTextChildren() && !noQuirksMode) {
+ if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
RootInlineBox* rootBox = root();
int& top = isHorizontal() ? y : x;
int& logicalHeight = isHorizontal() ? h : w;
@@ -1156,7 +1133,7 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, int tx, int ty)
// Constrain our background/border painting to the line top and bottom if necessary.
bool noQuirksMode = renderer()->document()->inNoQuirksMode();
- if (!hasTextChildren() && !noQuirksMode) {
+ if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) {
RootInlineBox* rootBox = root();
int& top = isHorizontal() ? y : x;
int& logicalHeight = isHorizontal() ? h : w;
@@ -1363,6 +1340,59 @@ int InlineFlowBox::computeUnderAnnotationAdjustment(int allowedPosition) const
return result;
}
+void InlineFlowBox::collectLeafBoxesInLogicalOrder(Vector<InlineBox*>& leafBoxesInLogicalOrder, CustomInlineBoxRangeReverse customReverseImplementation, void* userData) const
+{
+ InlineBox* leaf = firstLeafChild();
+
+ // FIXME: The reordering code is a copy of parts from BidiResolver::createBidiRunsForLine, operating directly on InlineBoxes, instead of BidiRuns.
+ // Investigate on how this code could possibly be shared.
+ unsigned char minLevel = 128;
+ unsigned char maxLevel = 0;
+
+ // First find highest and lowest levels, and initialize leafBoxesInLogicalOrder with the leaf boxes in visual order.
+ for (; leaf; leaf = leaf->nextLeafChild()) {
+ minLevel = min(minLevel, leaf->bidiLevel());
+ maxLevel = max(maxLevel, leaf->bidiLevel());
+ leafBoxesInLogicalOrder.append(leaf);
+ }
+
+ if (renderer()->style()->visuallyOrdered())
+ return;
+
+ // Reverse of reordering of the line (L2 according to Bidi spec):
+ // L2. From the highest level found in the text to the lowest odd level on each line,
+ // reverse any contiguous sequence of characters that are at that level or higher.
+
+ // Reversing the reordering of the line is only done up to the lowest odd level.
+ if (!(minLevel % 2))
+ ++minLevel;
+
+ Vector<InlineBox*>::iterator end = leafBoxesInLogicalOrder.end();
+ while (minLevel <= maxLevel) {
+ Vector<InlineBox*>::iterator it = leafBoxesInLogicalOrder.begin();
+ while (it != end) {
+ while (it != end) {
+ if ((*it)->bidiLevel() >= minLevel)
+ break;
+ ++it;
+ }
+ Vector<InlineBox*>::iterator first = it;
+ while (it != end) {
+ if ((*it)->bidiLevel() < minLevel)
+ break;
+ ++it;
+ }
+ Vector<InlineBox*>::iterator last = it;
+ if (customReverseImplementation) {
+ ASSERT(userData);
+ (*customReverseImplementation)(userData, first, last);
+ } else
+ std::reverse(first, last);
+ }
+ ++minLevel;
+ }
+}
+
#ifndef NDEBUG
void InlineFlowBox::checkConsistency() const
diff --git a/Source/WebCore/rendering/InlineFlowBox.h b/Source/WebCore/rendering/InlineFlowBox.h
index 918cf5d..9b6f8e4 100644
--- a/Source/WebCore/rendering/InlineFlowBox.h
+++ b/Source/WebCore/rendering/InlineFlowBox.h
@@ -45,6 +45,7 @@ public:
, m_nextLineBox(0)
, m_includeLogicalLeftEdge(false)
, m_includeLogicalRightEdge(false)
+ , m_descendantsHaveSameLineHeightAndBaseline(true)
#ifndef NDEBUG
, m_hasBadChildList(false)
#endif
@@ -55,6 +56,7 @@ public:
// text children must not apply. This change also means that gaps will exist between image bullet list items. Even when the list bullet
// is an image, the line is still considered to be immune from the quirk.
m_hasTextChildren = obj->style()->display() == LIST_ITEM;
+ m_hasTextDescendants = m_hasTextChildren;
}
#ifndef NDEBUG
@@ -74,6 +76,9 @@ public:
InlineBox* firstLeafChild() const;
InlineBox* lastLeafChild() const;
+ typedef void (*CustomInlineBoxRangeReverse)(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last);
+ void collectLeafBoxesInLogicalOrder(Vector<InlineBox*>&, CustomInlineBoxRangeReverse customReverseImplementation = 0, void* userData = 0) const;
+
virtual void setConstructed()
{
InlineBox::setConstructed();
@@ -154,11 +159,11 @@ public:
}
// Helper functions used during line construction and placement.
- void determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject);
+ void determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject, RenderObject* logicallyLastRunRenderer);
int getFlowSpacingLogicalWidth();
bool onEndChain(RenderObject* endObject);
float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&);
- void computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom,
+ void computeLogicalBoxHeights(RootInlineBox*, int& maxPositionTop, int& maxPositionBottom,
int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent,
bool strictMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&);
void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent,
@@ -181,6 +186,7 @@ public:
virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, bool&);
bool hasTextChildren() const { return m_hasTextChildren; }
+ bool hasTextDescendants() const { return m_hasTextDescendants; }
void checkConsistency() const;
void setHasBadChildList();
@@ -226,6 +232,14 @@ public:
void setLayoutOverflow(const IntRect&);
void setVisualOverflow(const IntRect&);
+ bool descendantsHaveSameLineHeightAndBaseline() const { return m_descendantsHaveSameLineHeightAndBaseline; }
+ void clearDescendantsHaveSameLineHeightAndBaseline()
+ {
+ m_descendantsHaveSameLineHeightAndBaseline = false;
+ if (parent() && parent()->descendantsHaveSameLineHeightAndBaseline())
+ parent()->clearDescendantsHaveSameLineHeightAndBaseline();
+ }
+
private:
void addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow);
void addTextBoxVisualOverflow(const InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, IntRect& logicalVisualOverflow);
@@ -245,6 +259,8 @@ protected:
bool m_includeLogicalLeftEdge : 1;
bool m_includeLogicalRightEdge : 1;
bool m_hasTextChildren : 1;
+ bool m_hasTextDescendants : 1;
+ bool m_descendantsHaveSameLineHeightAndBaseline : 1;
#ifndef NDEBUG
bool m_hasBadChildList;
diff --git a/Source/WebCore/rendering/InlineIterator.h b/Source/WebCore/rendering/InlineIterator.h
index 270364f..75d9763 100644
--- a/Source/WebCore/rendering/InlineIterator.h
+++ b/Source/WebCore/rendering/InlineIterator.h
@@ -34,43 +34,89 @@ namespace WebCore {
class InlineIterator {
public:
InlineIterator()
- : block(0)
- , obj(0)
- , pos(0)
- , nextBreakablePosition(-1)
+ : m_block(0)
+ , m_obj(0)
+ , m_pos(0)
+ , m_nextBreakablePosition(-1)
{
}
InlineIterator(RenderBlock* b, RenderObject* o, unsigned p)
- : block(b)
- , obj(o)
- , pos(p)
- , nextBreakablePosition(-1)
+ : m_block(b)
+ , m_obj(o)
+ , m_pos(p)
+ , m_nextBreakablePosition(-1)
{
}
+ void clear() { moveTo(0, 0); }
+
+ void moveToStartOf(RenderObject* object)
+ {
+ moveTo(object, 0);
+ }
+
+ void moveTo(RenderObject* object, unsigned offset, int nextBreak = -1)
+ {
+ m_obj = object;
+ m_pos = offset;
+ m_nextBreakablePosition = nextBreak;
+ }
+
void increment(InlineBidiResolver* resolver = 0);
bool atEnd() const;
UChar current() const;
ALWAYS_INLINE WTF::Unicode::Direction direction() const;
- RenderBlock* block;
- RenderObject* obj;
- unsigned pos;
- int nextBreakablePosition;
+ RenderBlock* m_block;
+ RenderObject* m_obj;
+ unsigned m_pos;
+ int m_nextBreakablePosition;
};
inline bool operator==(const InlineIterator& it1, const InlineIterator& it2)
{
- return it1.pos == it2.pos && it1.obj == it2.obj;
+ return it1.m_pos == it2.m_pos && it1.m_obj == it2.m_obj;
}
inline bool operator!=(const InlineIterator& it1, const InlineIterator& it2)
{
- return it1.pos != it2.pos || it1.obj != it2.obj;
+ return it1.m_pos != it2.m_pos || it1.m_obj != it2.m_obj;
+}
+
+static inline WTF::Unicode::Direction embedCharFromDirection(TextDirection dir, EUnicodeBidi unicodeBidi)
+{
+ using namespace WTF::Unicode;
+ if (unicodeBidi == Embed)
+ return dir == RTL ? RightToLeftEmbedding : LeftToRightEmbedding;
+ return dir == RTL ? RightToLeftOverride : LeftToRightOverride;
+}
+
+static inline void notifyResolverEnteredObject(InlineBidiResolver* resolver, RenderObject* object)
+{
+ if (!resolver || !object || !object->isRenderInline())
+ return;
+
+ RenderStyle* style = object->style();
+ EUnicodeBidi unicodeBidi = style->unicodeBidi();
+ if (unicodeBidi == UBNormal)
+ return;
+ resolver->embed(embedCharFromDirection(style->direction(), unicodeBidi), FromStyleOrDOM);
+}
+
+static inline void notifyResolverWillExitObject(InlineBidiResolver* resolver, RenderObject* object)
+{
+ if (!resolver || !object || !object->isRenderInline())
+ return;
+ if (object->style()->unicodeBidi() == UBNormal)
+ return;
+ resolver->embed(WTF::Unicode::PopDirectionalFormat, FromStyleOrDOM);
}
+// FIXME: This function is misleadingly named. It has little to do with bidi.
+// This function will iterate over inlines within a block, optionally notifying
+// a bidi resolver as it enters/exits inlines (so it can push/pop embedding levels).
static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, InlineBidiResolver* resolver = 0, bool skipInlines = true, bool* endOfInlinePtr = 0)
{
RenderObject* next = 0;
@@ -81,16 +127,7 @@ static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current,
next = 0;
if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned() && !current->isText()) {
next = current->firstChild();
- if (next && resolver && next->isRenderInline()) {
- EUnicodeBidi ub = next->style()->unicodeBidi();
- if (ub != UBNormal) {
- TextDirection dir = next->style()->direction();
- WTF::Unicode::Direction d = (ub == Embed
- ? (dir == RTL ? WTF::Unicode::RightToLeftEmbedding : WTF::Unicode::LeftToRightEmbedding)
- : (dir == RTL ? WTF::Unicode::RightToLeftOverride : WTF::Unicode::LeftToRightOverride));
- resolver->embed(d);
- }
- }
+ notifyResolverEnteredObject(resolver, next);
}
if (!next) {
@@ -101,24 +138,14 @@ static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current,
}
while (current && current != block) {
- if (resolver && current->isRenderInline() && current->style()->unicodeBidi() != UBNormal)
- resolver->embed(WTF::Unicode::PopDirectionalFormat);
+ notifyResolverWillExitObject(resolver, current);
next = current->nextSibling();
if (next) {
- if (resolver && next->isRenderInline()) {
- EUnicodeBidi ub = next->style()->unicodeBidi();
- if (ub != UBNormal) {
- TextDirection dir = next->style()->direction();
- WTF::Unicode::Direction d = (ub == Embed
- ? (dir == RTL ? WTF::Unicode::RightToLeftEmbedding: WTF::Unicode::LeftToRightEmbedding)
- : (dir == RTL ? WTF::Unicode::RightToLeftOverride : WTF::Unicode::LeftToRightOverride));
- resolver->embed(d);
- }
- }
+ notifyResolverEnteredObject(resolver, next);
break;
}
-
+
current = current->parent();
if (!skipInlines && current && current != block && current->isRenderInline()) {
next = current;
@@ -148,19 +175,10 @@ static inline RenderObject* bidiFirst(RenderBlock* block, InlineBidiResolver* re
{
if (!block->firstChild())
return 0;
-
+
RenderObject* o = block->firstChild();
if (o->isRenderInline()) {
- if (resolver) {
- EUnicodeBidi ub = o->style()->unicodeBidi();
- if (ub != UBNormal) {
- TextDirection dir = o->style()->direction();
- WTF::Unicode::Direction d = (ub == Embed
- ? (dir == RTL ? WTF::Unicode::RightToLeftEmbedding : WTF::Unicode::LeftToRightEmbedding)
- : (dir == RTL ? WTF::Unicode::RightToLeftOverride : WTF::Unicode::LeftToRightOverride));
- resolver->embed(d);
- }
- }
+ notifyResolverEnteredObject(resolver, o);
if (skipInlines && o->firstChild())
o = bidiNext(block, o, resolver, skipInlines);
else {
@@ -181,37 +199,32 @@ static inline RenderObject* bidiFirst(RenderBlock* block, InlineBidiResolver* re
inline void InlineIterator::increment(InlineBidiResolver* resolver)
{
- if (!obj)
+ if (!m_obj)
return;
- if (obj->isText()) {
- pos++;
- if (pos >= toRenderText(obj)->textLength()) {
- obj = bidiNext(block, obj, resolver);
- pos = 0;
- nextBreakablePosition = -1;
- }
- } else {
- obj = bidiNext(block, obj, resolver);
- pos = 0;
- nextBreakablePosition = -1;
+ if (m_obj->isText()) {
+ m_pos++;
+ if (m_pos < toRenderText(m_obj)->textLength())
+ return;
}
+ // bidiNext can return 0, so use moveTo instead of moveToStartOf
+ moveTo(bidiNext(m_block, m_obj, resolver), 0);
}
inline bool InlineIterator::atEnd() const
{
- return !obj;
+ return !m_obj;
}
inline UChar InlineIterator::current() const
{
- if (!obj || !obj->isText())
+ if (!m_obj || !m_obj->isText())
return 0;
- RenderText* text = toRenderText(obj);
- if (pos >= text->textLength())
+ RenderText* text = toRenderText(m_obj);
+ if (m_pos >= text->textLength())
return 0;
- return text->characters()[pos];
+ return text->characters()[m_pos];
}
ALWAYS_INLINE WTF::Unicode::Direction InlineIterator::direction() const
@@ -219,8 +232,8 @@ ALWAYS_INLINE WTF::Unicode::Direction InlineIterator::direction() const
if (UChar c = current())
return WTF::Unicode::direction(c);
- if (obj && obj->isListMarker())
- return obj->style()->isLeftToRightDirection() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;
+ if (m_obj && m_obj->isListMarker())
+ return m_obj->style()->isLeftToRightDirection() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;
return WTF::Unicode::OtherNeutral;
}
@@ -228,33 +241,33 @@ ALWAYS_INLINE WTF::Unicode::Direction InlineIterator::direction() const
template<>
inline void InlineBidiResolver::increment()
{
- current.increment(this);
+ m_current.increment(this);
}
template <>
inline void InlineBidiResolver::appendRun()
{
- if (!emptyRun && !eor.atEnd()) {
- int start = sor.pos;
- RenderObject *obj = sor.obj;
- while (obj && obj != eor.obj && obj != endOfLine.obj) {
+ if (!emptyRun && !m_eor.atEnd()) {
+ int start = m_sor.m_pos;
+ RenderObject* obj = m_sor.m_obj;
+ while (obj && obj != m_eor.m_obj && obj != endOfLine.m_obj) {
RenderBlock::appendRunsForObject(start, obj->length(), obj, *this);
start = 0;
- obj = bidiNext(sor.block, obj);
+ obj = bidiNext(m_sor.m_block, obj);
}
if (obj) {
- unsigned pos = obj == eor.obj ? eor.pos : UINT_MAX;
- if (obj == endOfLine.obj && endOfLine.pos <= pos) {
- reachedEndOfLine = true;
- pos = endOfLine.pos;
+ unsigned pos = obj == m_eor.m_obj ? m_eor.m_pos : UINT_MAX;
+ if (obj == endOfLine.m_obj && endOfLine.m_pos <= pos) {
+ m_reachedEndOfLine = true;
+ pos = endOfLine.m_pos;
}
// It's OK to add runs for zero-length RenderObjects, just don't make the run larger than it should be
- int end = obj->length() ? pos+1 : 0;
+ int end = obj->length() ? pos + 1 : 0;
RenderBlock::appendRunsForObject(start, end, obj, *this);
}
- eor.increment();
- sor = eor;
+ m_eor.increment();
+ m_sor = m_eor;
}
m_direction = WTF::Unicode::OtherNeutral;
diff --git a/Source/WebCore/rendering/InlineTextBox.cpp b/Source/WebCore/rendering/InlineTextBox.cpp
index 3c3e450..b614f0f 100644
--- a/Source/WebCore/rendering/InlineTextBox.cpp
+++ b/Source/WebCore/rendering/InlineTextBox.cpp
@@ -163,7 +163,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_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride),
+ IntRect r = enclosingIntRect(f.selectionRectForText(TextRun(characters, len, textObj->allowTabs(), textPos(), m_expansion, expansionBehavior(), !isLeftToRightDirection(), m_dirOverride),
IntPoint(), selHeight, sPos, ePos));
int logicalWidth = r.width();
@@ -427,6 +427,14 @@ bool InlineTextBox::getEmphasisMarkPosition(RenderStyle* style, TextEmphasisPosi
return !rubyText || !rubyText->firstLineBox();
}
+enum RotationDirection { Counterclockwise, Clockwise };
+
+static inline AffineTransform rotation(const FloatRect& boxRect, RotationDirection clockwise)
+{
+ return clockwise ? AffineTransform(0, 1, -1, 0, boxRect.x() + boxRect.maxY(), boxRect.maxY() - boxRect.x())
+ : AffineTransform(0, -1, 1, 0, boxRect.x() - boxRect.maxY(), boxRect.x() + boxRect.maxY());
+}
+
void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
{
if (isLineBreak() || !paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE ||
@@ -485,26 +493,22 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
FloatPoint boxOrigin = locationIncludingFlipping();
boxOrigin.move(tx, ty);
FloatRect boxRect(boxOrigin, IntSize(logicalWidth(), logicalHeight()));
- FloatPoint textOrigin = FloatPoint(boxOrigin.x(), boxOrigin.y() + styleToUse->fontMetrics().ascent());
- RenderCombineText* combinedText = styleToUse->hasTextCombine() ? toRenderCombineText(textRenderer()) : 0;
- bool shouldRotate = !isHorizontal() && (!combinedText || !combinedText->isCombined());
- if (shouldRotate) {
- context->save();
- context->translate(boxRect.x(), boxRect.maxY());
- context->rotate(static_cast<float>(deg2rad(90.)));
- context->translate(-boxRect.x(), -boxRect.maxY());
- }
-
-
+ RenderCombineText* combinedText = styleToUse->hasTextCombine() && textRenderer()->isCombineText() && toRenderCombineText(textRenderer())->isCombined() ? toRenderCombineText(textRenderer()) : 0;
+
+ bool shouldRotate = !isHorizontal() && !combinedText;
+ if (shouldRotate)
+ context->concatCTM(rotation(boxRect, Clockwise));
+
// Determine whether or not we have composition underlines to draw.
bool containsComposition = renderer()->node() && renderer()->frame()->editor()->compositionNode() == renderer()->node();
bool useCustomUnderlines = containsComposition && renderer()->frame()->editor()->compositionUsesCustomUnderlines();
// Set our font.
- int d = styleToUse->textDecorationsInEffect();
const Font& font = styleToUse->font();
+ FloatPoint textOrigin = FloatPoint(boxOrigin.x(), boxOrigin.y() + font.fontMetrics().ascent());
+
if (combinedText)
combinedText->adjustTextOrigin(textOrigin, boxRect);
@@ -618,7 +622,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
if (hasHyphen())
adjustCharactersAndLengthForHyphen(charactersWithHyphen, styleToUse, characters, length);
- TextRun textRun(characters, length, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || styleToUse->visuallyOrdered());
+ TextRun textRun(characters, length, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(), !isLeftToRightDirection(), m_dirOverride || styleToUse->visuallyOrdered());
int sPos = 0;
int ePos = 0;
@@ -653,11 +657,21 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
if (!emphasisMark.isEmpty()) {
updateGraphicsContext(context, emphasisMarkColor, textStrokeColor, textStrokeWidth, styleToUse->colorSpace());
+
+ static TextRun objectReplacementCharacterTextRun(&objectReplacementCharacter, 1);
+ TextRun& emphasisMarkTextRun = combinedText ? objectReplacementCharacterTextRun : textRun;
+ FloatPoint emphasisMarkTextOrigin = combinedText ? FloatPoint(boxOrigin.x() + boxRect.width() / 2, boxOrigin.y() + font.fontMetrics().ascent()) : textOrigin;
+ if (combinedText)
+ context->concatCTM(rotation(boxRect, Clockwise));
+
if (!paintSelectedTextSeparately || ePos <= sPos) {
// FIXME: Truncate right-to-left text correctly.
- paintTextWithShadows(context, font, textRun, emphasisMark, emphasisMarkOffset, 0, length, length, textOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
+ paintTextWithShadows(context, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, 0, length, length, emphasisMarkTextOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
} else
- paintTextWithShadows(context, font, textRun, emphasisMark, emphasisMarkOffset, ePos, sPos, length, textOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
+ paintTextWithShadows(context, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, ePos, sPos, length, emphasisMarkTextOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
+
+ if (combinedText)
+ context->concatCTM(rotation(boxRect, Counterclockwise));
}
if (textStrokeWidth > 0)
@@ -673,16 +687,27 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
paintTextWithShadows(context, font, textRun, nullAtom, 0, sPos, ePos, length, textOrigin, boxRect, selectionShadow, selectionStrokeWidth > 0, isHorizontal());
if (!emphasisMark.isEmpty()) {
updateGraphicsContext(context, selectionEmphasisMarkColor, textStrokeColor, textStrokeWidth, styleToUse->colorSpace());
- paintTextWithShadows(context, font, textRun, emphasisMark, emphasisMarkOffset, sPos, ePos, length, textOrigin, boxRect, selectionShadow, selectionStrokeWidth > 0, isHorizontal());
+
+ static TextRun objectReplacementCharacterTextRun(&objectReplacementCharacter, 1);
+ TextRun& emphasisMarkTextRun = combinedText ? objectReplacementCharacterTextRun : textRun;
+ FloatPoint emphasisMarkTextOrigin = combinedText ? FloatPoint(boxOrigin.x() + boxRect.width() / 2, boxOrigin.y() + font.fontMetrics().ascent()) : textOrigin;
+ if (combinedText)
+ context->concatCTM(rotation(boxRect, Clockwise));
+
+ paintTextWithShadows(context, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, sPos, ePos, length, emphasisMarkTextOrigin, boxRect, selectionShadow, selectionStrokeWidth > 0, isHorizontal());
+
+ if (combinedText)
+ context->concatCTM(rotation(boxRect, Counterclockwise));
}
if (selectionStrokeWidth > 0)
context->restore();
}
// Paint decorations
- if (d != TDNONE && paintInfo.phase != PaintPhaseSelection) {
+ int textDecorations = styleToUse->textDecorationsInEffect();
+ if (textDecorations != TDNONE && paintInfo.phase != PaintPhaseSelection) {
updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth, styleToUse->colorSpace());
- paintDecoration(context, boxOrigin, d, textShadow);
+ paintDecoration(context, boxOrigin, textDecorations, textShadow);
}
if (paintInfo.phase == PaintPhaseForeground) {
@@ -715,7 +740,7 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty)
}
if (shouldRotate)
- context->restore();
+ context->concatCTM(rotation(boxRect, Counterclockwise));
}
void InlineTextBox::selectionStartEnd(int& sPos, int& ePos)
@@ -772,7 +797,7 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& b
int selHeight = selectionHeight();
FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY);
context->clip(FloatRect(localOrigin, FloatSize(m_logicalWidth, selHeight)));
- context->drawHighlightForText(font, TextRun(characters, length, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(),
+ context->drawHighlightForText(font, TextRun(characters, length, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(),
!isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()),
localOrigin, selHeight, c, style->colorSpace(), sPos, ePos);
context->restore();
@@ -796,7 +821,7 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* context, const F
int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop();
int selHeight = selectionHeight();
FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY);
- context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(),
+ context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(),
!isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()),
localOrigin, selHeight, c, style->colorSpace(), sPos, ePos);
context->restore();
@@ -958,7 +983,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, const Floa
int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop();
int selHeight = selectionHeight();
FloatPoint startPoint(boxOrigin.x(), boxOrigin.y() - deltaY);
- TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered());
+ TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered());
// FIXME: Convert the document markers to float rects.
IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, selHeight, startPosition, endPosition));
@@ -1003,7 +1028,7 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const FloatPoint&
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_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered());
+ TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(), !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, selectionTop()), selHeight, sPos, ePos));
@@ -1031,7 +1056,7 @@ void InlineTextBox::computeRectForReplacementMarker(const DocumentMarker& marker
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_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered());
+ TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered());
IntPoint startPoint = IntPoint(m_x, y);
// Compute and store the rect associated with this marker.
@@ -1192,7 +1217,7 @@ int InlineTextBox::offsetForPosition(float lineOffset, bool includePartialGlyphs
RenderStyle* style = text->style(m_firstLine);
const Font* f = &style->font();
int offset = f->offsetForPosition(TextRun(textRenderer()->text()->characters() + m_start, m_len,
- textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()),
+ textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(), !isLeftToRightDirection(), m_dirOverride || style->visuallyOrdered()),
lineOffset - logicalLeft(), includePartialGlyphs);
if (blockIsInOppositeDirection && (!offset || offset == m_len))
return !offset ? m_len : 0;
@@ -1212,7 +1237,7 @@ float InlineTextBox::positionForOffset(int offset) const
int from = !isLeftToRightDirection() ? offset - m_start : 0;
int to = !isLeftToRightDirection() ? m_len : offset - m_start;
// FIXME: Do we need to add rightBearing here?
- return f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, trailingExpansionBehavior(), !isLeftToRightDirection(), m_dirOverride),
+ return f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(), !isLeftToRightDirection(), m_dirOverride),
IntPoint(logicalLeft(), 0), 0, from, to).maxX();
}
diff --git a/Source/WebCore/rendering/InlineTextBox.h b/Source/WebCore/rendering/InlineTextBox.h
index d894b85..98a1b78 100644
--- a/Source/WebCore/rendering/InlineTextBox.h
+++ b/Source/WebCore/rendering/InlineTextBox.h
@@ -69,6 +69,10 @@ public:
bool hasHyphen() const { return m_hasEllipsisBoxOrHyphen; }
void setHasHyphen(bool hasHyphen) { m_hasEllipsisBoxOrHyphen = hasHyphen; }
+
+ bool canHaveLeadingExpansion() const { return m_hasSelectedChildrenOrCanHaveLeadingExpansion; }
+ void setCanHaveLeadingExpansion(bool canHaveLeadingExpansion) { m_hasSelectedChildrenOrCanHaveLeadingExpansion = canHaveLeadingExpansion; }
+
static inline bool compareByStart(const InlineTextBox* first, const InlineTextBox* second) { return first->start() < second->start(); }
virtual int baselinePosition(FontBaseline) const;
@@ -158,7 +162,11 @@ private:
void paintTextMatchMarker(GraphicsContext*, const FloatPoint& boxOrigin, const DocumentMarker&, RenderStyle*, const Font&);
void computeRectForReplacementMarker(const DocumentMarker&, RenderStyle*, const Font&);
- TextRun::TrailingExpansionBehavior trailingExpansionBehavior() const { return m_expansion && nextLeafChild() ? TextRun::AllowTrailingExpansion : TextRun::ForbidTrailingExpansion; }
+ TextRun::ExpansionBehavior expansionBehavior() const
+ {
+ return (canHaveLeadingExpansion() ? TextRun::AllowLeadingExpansion : TextRun::ForbidLeadingExpansion)
+ | (m_expansion && nextLeafChild() ? TextRun::AllowTrailingExpansion : TextRun::ForbidTrailingExpansion);
+ }
};
inline RenderText* InlineTextBox::textRenderer() const
diff --git a/Source/WebCore/rendering/MediaControlElements.cpp b/Source/WebCore/rendering/MediaControlElements.cpp
index 32aac90..07df4d9 100644
--- a/Source/WebCore/rendering/MediaControlElements.cpp
+++ b/Source/WebCore/rendering/MediaControlElements.cpp
@@ -41,9 +41,11 @@
#include "MediaControls.h"
#include "MouseEvent.h"
#include "Page.h"
+#include "RenderFlexibleBox.h"
#include "RenderMedia.h"
#include "RenderSlider.h"
#include "RenderTheme.h"
+#include "RenderView.h"
#include "Settings.h"
namespace WebCore {
@@ -250,11 +252,41 @@ const AtomicString& MediaControlTimelineContainerElement::shadowPseudoId() const
// ----------------------------
+class RenderMediaVolumeSliderContainer : public RenderBlock {
+public:
+ RenderMediaVolumeSliderContainer(Node*);
+
+private:
+ virtual void layout();
+};
+
+RenderMediaVolumeSliderContainer::RenderMediaVolumeSliderContainer(Node* node)
+ : RenderBlock(node)
+{
+}
+
+void RenderMediaVolumeSliderContainer::layout()
+{
+ RenderBlock::layout();
+ if (style()->display() == NONE || !previousSibling() || !previousSibling()->isBox())
+ return;
+
+ RenderBox* buttonBox = toRenderBox(previousSibling());
+
+ if (view())
+ view()->disableLayoutState();
+
+ IntPoint offset = theme()->volumeSliderOffsetFromMuteButton(buttonBox, IntSize(width(), height()));
+ setX(offset.x() + buttonBox->offsetLeft());
+ setY(offset.y() + buttonBox->offsetTop());
+
+ if (view())
+ view()->enableLayoutState();
+}
+
inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(HTMLMediaElement* mediaElement)
: MediaControlElement(mediaElement)
, m_isVisible(false)
- , m_x(0)
- , m_y(0)
{
}
@@ -263,12 +295,15 @@ PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderCon
return adoptRef(new MediaControlVolumeSliderContainerElement(mediaElement));
}
+RenderObject* MediaControlVolumeSliderContainerElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+ return new (arena) RenderMediaVolumeSliderContainer(this);
+}
+
PassRefPtr<RenderStyle> MediaControlVolumeSliderContainerElement::styleForElement()
{
RefPtr<RenderStyle> style = MediaControlElement::styleForElement();
style->setPosition(AbsolutePosition);
- style->setLeft(Length(m_x, Fixed));
- style->setTop(Length(m_y, Fixed));
style->setDisplay(m_isVisible ? BLOCK : NONE);
return style;
}
@@ -280,14 +315,6 @@ void MediaControlVolumeSliderContainerElement::setVisible(bool visible)
m_isVisible = visible;
}
-void MediaControlVolumeSliderContainerElement::setPosition(int x, int y)
-{
- if (x == m_x && y == m_y)
- return;
- m_x = x;
- m_y = y;
-}
-
bool MediaControlVolumeSliderContainerElement::hitTest(const IntPoint& absPoint)
{
if (renderer() && renderer()->style()->hasAppearance())
@@ -776,6 +803,7 @@ PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(HTML
{
RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(mediaElement));
timeline->setType("range");
+ timeline->setAttribute(precisionAttr, "float");
return timeline.release();
}
@@ -841,6 +869,9 @@ PassRefPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::cre
{
RefPtr<MediaControlVolumeSliderElement> slider = adoptRef(new MediaControlVolumeSliderElement(mediaElement));
slider->setType("range");
+ slider->setAttribute(precisionAttr, "float");
+ slider->setAttribute(maxAttr, "1");
+ slider->setAttribute(valueAttr, String::number(mediaElement->volume()));
return slider.release();
}
@@ -882,6 +913,29 @@ const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const
// ----------------------------
+inline MediaControlFullscreenVolumeSliderElement::MediaControlFullscreenVolumeSliderElement(HTMLMediaElement* mediaElement)
+: MediaControlVolumeSliderElement(mediaElement)
+{
+}
+
+PassRefPtr<MediaControlFullscreenVolumeSliderElement> MediaControlFullscreenVolumeSliderElement::create(HTMLMediaElement* mediaElement)
+{
+ RefPtr<MediaControlFullscreenVolumeSliderElement> slider = adoptRef(new MediaControlFullscreenVolumeSliderElement(mediaElement));
+ slider->setType("range");
+ slider->setAttribute(precisionAttr, "float");
+ slider->setAttribute(maxAttr, "1");
+ slider->setAttribute(valueAttr, String::number(mediaElement->volume()));
+ return slider.release();
+}
+
+const AtomicString& MediaControlFullscreenVolumeSliderElement::shadowPseudoId() const
+{
+ DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-slider"));
+ return id;
+}
+
+// ----------------------------
+
inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(HTMLMediaElement* mediaElement)
: MediaControlInputElement(mediaElement, MediaFullscreenButton)
{
@@ -924,36 +978,95 @@ const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const
// ----------------------------
-inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(HTMLMediaElement* mediaElement)
- : MediaControlElement(mediaElement)
- , m_currentValue(0)
- , m_isVisible(true)
+inline MediaControlFullscreenVolumeMinButtonElement::MediaControlFullscreenVolumeMinButtonElement(HTMLMediaElement* mediaElement)
+: MediaControlInputElement(mediaElement, MediaUnMuteButton)
{
}
-PassRefPtr<RenderStyle> MediaControlTimeDisplayElement::styleForElement()
+PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> MediaControlFullscreenVolumeMinButtonElement::create(HTMLMediaElement* mediaElement)
{
- RefPtr<RenderStyle> style = MediaControlElement::styleForElement();
- if (!m_isVisible) {
- style = RenderStyle::clone(style.get());
- style->setWidth(Length(0, Fixed));
+ RefPtr<MediaControlFullscreenVolumeMinButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMinButtonElement(mediaElement));
+ button->setType("button");
+ return button.release();
+}
+
+void MediaControlFullscreenVolumeMinButtonElement::defaultEventHandler(Event* event)
+{
+ if (event->type() == eventNames().clickEvent) {
+ ExceptionCode code = 0;
+ mediaElement()->setVolume(0, code);
+ event->setDefaultHandled();
}
- return style;
+ HTMLInputElement::defaultEventHandler(event);
}
-void MediaControlTimeDisplayElement::setVisible(bool visible)
+const AtomicString& MediaControlFullscreenVolumeMinButtonElement::shadowPseudoId() const
{
- if (visible == m_isVisible)
- return;
- m_isVisible = visible;
+ DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-min-button"));
+ return id;
+}
- // This function is used during the RenderMedia::layout()
- // call, where we cannot change the renderer at this time.
- if (!renderer() || !renderer()->style())
- return;
+// ----------------------------
- RefPtr<RenderStyle> style = styleForElement();
- renderer()->setStyle(style.get());
+inline MediaControlFullscreenVolumeMaxButtonElement::MediaControlFullscreenVolumeMaxButtonElement(HTMLMediaElement* mediaElement)
+: MediaControlInputElement(mediaElement, MediaMuteButton)
+{
+}
+
+PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> MediaControlFullscreenVolumeMaxButtonElement::create(HTMLMediaElement* mediaElement)
+{
+ RefPtr<MediaControlFullscreenVolumeMaxButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMaxButtonElement(mediaElement));
+ button->setType("button");
+ return button.release();
+}
+
+void MediaControlFullscreenVolumeMaxButtonElement::defaultEventHandler(Event* event)
+{
+ if (event->type() == eventNames().clickEvent) {
+ ExceptionCode code = 0;
+ mediaElement()->setVolume(1, code);
+ event->setDefaultHandled();
+ }
+ HTMLInputElement::defaultEventHandler(event);
+}
+
+const AtomicString& MediaControlFullscreenVolumeMaxButtonElement::shadowPseudoId() const
+{
+ DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-max-button"));
+ return id;
+}
+
+// ----------------------------
+
+class RenderMediaControlTimeDisplay : public RenderFlexibleBox {
+public:
+ RenderMediaControlTimeDisplay(Node*);
+
+private:
+ virtual void layout();
+};
+
+RenderMediaControlTimeDisplay::RenderMediaControlTimeDisplay(Node* node)
+ : RenderFlexibleBox(node)
+{
+}
+
+// We want the timeline slider to be at least 100 pixels wide.
+// FIXME: Eliminate hard-coded widths altogether.
+static const int minWidthToDisplayTimeDisplays = 45 + 100 + 45;
+
+void RenderMediaControlTimeDisplay::layout()
+{
+ RenderFlexibleBox::layout();
+ RenderBox* timelineContainerBox = parentBox();
+ if (timelineContainerBox && timelineContainerBox->width() < minWidthToDisplayTimeDisplays)
+ setWidth(0);
+}
+
+inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(HTMLMediaElement* mediaElement)
+ : MediaControlElement(mediaElement)
+ , m_currentValue(0)
+{
}
void MediaControlTimeDisplayElement::setCurrentValue(float time)
@@ -961,6 +1074,11 @@ void MediaControlTimeDisplayElement::setCurrentValue(float time)
m_currentValue = time;
}
+RenderObject* MediaControlTimeDisplayElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+ return new (arena) RenderMediaControlTimeDisplay(this);
+}
+
// ----------------------------
PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(HTMLMediaElement* mediaElement)
diff --git a/Source/WebCore/rendering/MediaControlElements.h b/Source/WebCore/rendering/MediaControlElements.h
index 44e8811..77116e3 100644
--- a/Source/WebCore/rendering/MediaControlElements.h
+++ b/Source/WebCore/rendering/MediaControlElements.h
@@ -142,16 +142,16 @@ public:
virtual PassRefPtr<RenderStyle> styleForElement();
void setVisible(bool);
bool isVisible() { return m_isVisible; }
- void setPosition(int x, int y);
bool hitTest(const IntPoint& absPoint);
private:
MediaControlVolumeSliderContainerElement(HTMLMediaElement*);
+
+ virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
virtual MediaControlElementType displayType() const;
virtual const AtomicString& shadowPseudoId() const;
bool m_isVisible;
- int m_x, m_y;
};
// ----------------------------
@@ -372,9 +372,10 @@ public:
virtual void defaultEventHandler(Event*);
void update();
-private:
+protected:
MediaControlVolumeSliderElement(HTMLMediaElement*);
+private:
virtual const AtomicString& shadowPseudoId() const;
};
@@ -394,10 +395,48 @@ private:
// ----------------------------
-class MediaControlTimeDisplayElement : public MediaControlElement {
+class MediaControlFullscreenVolumeSliderElement : public MediaControlVolumeSliderElement {
public:
- void setVisible(bool);
+ static PassRefPtr<MediaControlFullscreenVolumeSliderElement> create(HTMLMediaElement*);
+
+private:
+ MediaControlFullscreenVolumeSliderElement(HTMLMediaElement*);
+
+ virtual const AtomicString& shadowPseudoId() const;
+};
+
+// ----------------------------
+
+class MediaControlFullscreenVolumeMinButtonElement : public MediaControlInputElement {
+public:
+ static PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> create(HTMLMediaElement*);
+
+ virtual void defaultEventHandler(Event*);
+
+private:
+ MediaControlFullscreenVolumeMinButtonElement(HTMLMediaElement*);
+
+ virtual const AtomicString& shadowPseudoId() const;
+};
+
+// ----------------------------
+
+class MediaControlFullscreenVolumeMaxButtonElement : public MediaControlInputElement {
+public:
+ static PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> create(HTMLMediaElement*);
+
+ virtual void defaultEventHandler(Event*);
+
+private:
+ MediaControlFullscreenVolumeMaxButtonElement(HTMLMediaElement*);
+
+ virtual const AtomicString& shadowPseudoId() const;
+};
+
+// ----------------------------
+class MediaControlTimeDisplayElement : public MediaControlElement {
+public:
void setCurrentValue(float);
float currentValue() const { return m_currentValue; }
@@ -405,9 +444,9 @@ protected:
MediaControlTimeDisplayElement(HTMLMediaElement*);
private:
- virtual PassRefPtr<RenderStyle> styleForElement();
+ virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+
float m_currentValue;
- bool m_isVisible;
};
// ----------------------------
diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp
index 7488ff5..919e23b 100644
--- a/Source/WebCore/rendering/RenderBlock.cpp
+++ b/Source/WebCore/rendering/RenderBlock.cpp
@@ -34,6 +34,7 @@
#include "HTMLFormElement.h"
#include "HTMLNames.h"
#include "HitTestResult.h"
+#include "InlineIterator.h"
#include "InlineTextBox.h"
#include "PaintInfo.h"
#include "RenderCombineText.h"
@@ -51,6 +52,7 @@
#include "Settings.h"
#include "TextRun.h"
#include "TransformState.h"
+#include "visible_units.h"
#include <wtf/StdLibExtras.h>
#ifdef ANDROID_LAYOUT
@@ -243,8 +245,7 @@ void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
// FIXME: We could save this call when the change only affected non-inherited properties
for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
if (child->isAnonymousBlock()) {
- RefPtr<RenderStyle> newStyle = RenderStyle::create();
- newStyle->inheritFrom(style());
+ RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
if (style()->specifiesColumns()) {
if (child->style()->specifiesColumns())
newStyle->inheritColumnPropertiesFrom(style());
@@ -937,6 +938,9 @@ static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObje
if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation())
return false;
+ if (oldChild->parent() && oldChild->parent()->isDetails())
+ return false;
+
if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation() || toRenderBlock(prev)->beingDestroyed()))
|| (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation() || toRenderBlock(next)->beingDestroyed())))
return false;
@@ -979,8 +983,7 @@ void RenderBlock::removeChild(RenderObject* oldChild)
// to clear out inherited column properties by just making a new style, and to also clear the
// column span flag if it is set.
ASSERT(!inlineChildrenBlock->continuation());
- RefPtr<RenderStyle> newStyle = RenderStyle::create();
- newStyle->inheritFrom(style());
+ RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlock->hasLayer());
inlineChildrenBlock->setStyle(newStyle);
@@ -1136,7 +1139,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageLogicalHeight)
if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
return; // cause us to come in here. Just bail.
- if (!relayoutChildren && layoutOnlyPositionedObjects())
+ if (!relayoutChildren && simplifiedLayout())
return;
LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout());
@@ -1292,7 +1295,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageLogicalHeight)
}
IntRect repaintRect;
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
repaintRect = IntRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
else
repaintRect = IntRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
@@ -1331,17 +1334,21 @@ void RenderBlock::addOverflowFromChildren()
ColumnInfo* colInfo = columnInfo();
if (columnCount(colInfo)) {
IntRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
- if (style()->isHorizontalWritingMode()) {
+ if (isHorizontalWritingMode()) {
int overflowLeft = !style()->isLeftToRightDirection() ? min(0, lastRect.x()) : 0;
int overflowRight = style()->isLeftToRightDirection() ? max(width(), lastRect.maxX()) : 0;
int overflowHeight = borderBefore() + paddingBefore() + colInfo->columnHeight();
addLayoutOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight));
+ if (!hasOverflowClip())
+ addVisualOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight));
} else {
IntRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
int overflowTop = !style()->isLeftToRightDirection() ? min(0, lastRect.y()) : 0;
int overflowBottom = style()->isLeftToRightDirection() ? max(height(), lastRect.maxY()) : 0;
int overflowWidth = borderBefore() + paddingBefore() + colInfo->columnHeight();
addLayoutOverflow(IntRect(0, overflowTop, overflowWidth, overflowBottom - overflowTop));
+ if (!hasOverflowClip())
+ addVisualOverflow(IntRect(0, overflowTop, overflowWidth, overflowBottom - overflowTop));
}
}
}
@@ -1364,7 +1371,7 @@ void RenderBlock::computeOverflow(int oldClientAfterEdge, bool recomputeFloats)
// be considered reachable.
IntRect clientRect(clientBoxRect());
IntRect rectToApply;
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
rectToApply = IntRect(clientRect.x(), clientRect.y(), 1, max(0, oldClientAfterEdge - clientRect.y()));
else
rectToApply = IntRect(clientRect.x(), clientRect.y(), max(0, oldClientAfterEdge - clientRect.x()), 1);
@@ -1422,34 +1429,31 @@ bool RenderBlock::expandsToEncloseOverhangingFloats() const
void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
{
- bool isHorizontal = style()->isHorizontalWritingMode();
- bool hasStaticInlinePosition = child->style()->hasStaticInlinePosition(isHorizontal);
+ bool isHorizontal = isHorizontalWritingMode();
bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
RenderLayer* childLayer = child->layer();
- if (hasStaticInlinePosition)
- childLayer->setStaticInlinePosition(borderAndPaddingStart());
-
- if (hasStaticBlockPosition) {
- int logicalTop = logicalHeight();
- if (!marginInfo.canCollapseWithMarginBefore()) {
- child->computeBlockDirectionMargins(this);
- int marginBefore = marginBeforeForChild(child);
- int collapsedBeforePos = marginInfo.positiveMargin();
- int collapsedBeforeNeg = marginInfo.negativeMargin();
- if (marginBefore > 0) {
- if (marginBefore > collapsedBeforePos)
- collapsedBeforePos = marginBefore;
- } else {
- if (-marginBefore > collapsedBeforeNeg)
- collapsedBeforeNeg = -marginBefore;
- }
- logicalTop += (collapsedBeforePos - collapsedBeforeNeg) - marginBefore;
+ childLayer->setStaticInlinePosition(borderAndPaddingStart());
+
+ int logicalTop = logicalHeight();
+ if (!marginInfo.canCollapseWithMarginBefore()) {
+ child->computeBlockDirectionMargins(this);
+ int marginBefore = marginBeforeForChild(child);
+ int collapsedBeforePos = marginInfo.positiveMargin();
+ int collapsedBeforeNeg = marginInfo.negativeMargin();
+ if (marginBefore > 0) {
+ if (marginBefore > collapsedBeforePos)
+ collapsedBeforePos = marginBefore;
+ } else {
+ if (-marginBefore > collapsedBeforeNeg)
+ collapsedBeforeNeg = -marginBefore;
}
- if (childLayer->staticBlockPosition() != logicalTop) {
- childLayer->setStaticBlockPosition(logicalTop);
+ logicalTop += (collapsedBeforePos - collapsedBeforeNeg) - marginBefore;
+ }
+ if (childLayer->staticBlockPosition() != logicalTop) {
+ childLayer->setStaticBlockPosition(logicalTop);
+ if (hasStaticBlockPosition)
child->setChildNeedsLayout(true, false);
- }
}
}
@@ -1818,7 +1822,7 @@ void RenderBlock::handleAfterSideOfBlock(int beforeSide, int afterSide, MarginIn
void RenderBlock::setLogicalLeftForChild(RenderBox* child, int logicalLeft, ApplyLayoutDeltaMode applyDelta)
{
- if (style()->isHorizontalWritingMode()) {
+ if (isHorizontalWritingMode()) {
if (applyDelta == ApplyLayoutDelta)
view()->addLayoutDelta(IntSize(child->x() - logicalLeft, 0));
child->setX(logicalLeft);
@@ -1831,7 +1835,7 @@ void RenderBlock::setLogicalLeftForChild(RenderBox* child, int logicalLeft, Appl
void RenderBlock::setLogicalTopForChild(RenderBox* child, int logicalTop, ApplyLayoutDeltaMode applyDelta)
{
- if (style()->isHorizontalWritingMode()) {
+ if (isHorizontalWritingMode()) {
if (applyDelta == ApplyLayoutDelta)
view()->addLayoutDelta(IntSize(0, child->y() - logicalTop));
child->setY(logicalTop);
@@ -2080,21 +2084,58 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int
ASSERT(oldLayoutDelta == view()->layoutDelta());
}
-bool RenderBlock::layoutOnlyPositionedObjects()
+void RenderBlock::simplifiedNormalFlowLayout()
{
- if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout())
+ if (childrenInline()) {
+ ListHashSet<RootInlineBox*> lineBoxes;
+ bool endOfInline = false;
+ RenderObject* o = bidiFirst(this, 0, false);
+ while (o) {
+ if (!o->isPositioned() && (o->isReplaced() || o->isFloating())) {
+ o->layoutIfNeeded();
+ if (toRenderBox(o)->inlineBoxWrapper()) {
+ RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root();
+ lineBoxes.add(box);
+ }
+ } else if (o->isText() || (o->isRenderInline() && !endOfInline))
+ o->setNeedsLayout(false);
+ o = bidiNext(this, o, 0, false, &endOfInline);
+ }
+
+ // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
+ GlyphOverflowAndFallbackFontsMap textBoxDataMap;
+ for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
+ RootInlineBox* box = *it;
+ box->computeOverflow(box->lineTop(), box->lineBottom(), document()->inNoQuirksMode(), textBoxDataMap);
+ }
+ } else {
+ for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
+ if (!box->isPositioned())
+ box->layoutIfNeeded();
+ }
+ }
+}
+
+bool RenderBlock::simplifiedLayout()
+{
+ if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout())
return false;
LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
-
+
if (needsPositionedMovementLayout()) {
tryLayoutDoingPositionedMovementOnly();
if (needsLayout())
return false;
}
- // All we have to is lay out our positioned objects.
- layoutPositionedObjects(false);
+ // Lay out positioned descendants or objects that just need to recompute overflow.
+ if (needsSimplifiedNormalFlowLayout())
+ simplifiedNormalFlowLayout();
+
+ // Lay out our positioned objects if our positioned child bit is set.
+ if (posChildNeedsLayout())
+ layoutPositionedObjects(false);
// Recompute our overflow information.
// FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
@@ -2137,7 +2178,7 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
// non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
// objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
// positioned explicitly) this should not incur a performance penalty.
- if (relayoutChildren || (r->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()) && r->parent() != this && r->parent()->isBlockFlow()))
+ if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this && r->parent()->isBlockFlow()))
r->setChildNeedsLayout(true, false);
// If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
@@ -2221,6 +2262,7 @@ void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty)
// paints the root's background.
if (!isRoot()) {
IntRect overflowBox = visualOverflowRect();
+ flipForWritingMode(overflowBox);
overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
overflowBox.move(tx, ty);
if (!overflowBox.intersects(paintInfo.rect))
@@ -2259,7 +2301,7 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty)
for (unsigned i = 0; i < colCount; i++) {
IntRect colRect = columnRectAt(colInfo, i);
- int inlineDirectionSize = style()->isHorizontalWritingMode() ? colRect.width() : colRect.height();
+ int inlineDirectionSize = isHorizontalWritingMode() ? colRect.width() : colRect.height();
// Move to the next position.
if (style()->isLeftToRightDirection()) {
@@ -2272,10 +2314,10 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty)
// Now paint the column rule.
if (i < colCount - 1) {
- int ruleLeft = style()->isHorizontalWritingMode() ? tx + ruleLogicalLeft - ruleWidth / 2 + ruleAdd : tx + borderBefore() + paddingBefore();
- int ruleRight = style()->isHorizontalWritingMode() ? ruleLeft + ruleWidth : ruleLeft + contentWidth();
- int ruleTop = style()->isHorizontalWritingMode() ? ty + borderTop() + paddingTop() : ty + ruleLogicalLeft - ruleWidth / 2 + ruleAdd;
- int ruleBottom = style()->isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleWidth;
+ int ruleLeft = isHorizontalWritingMode() ? tx + ruleLogicalLeft - ruleWidth / 2 + ruleAdd : tx + borderBefore() + paddingBefore();
+ int ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleWidth : ruleLeft + contentWidth();
+ int ruleTop = isHorizontalWritingMode() ? ty + borderTop() + paddingTop() : ty + ruleLogicalLeft - ruleWidth / 2 + ruleAdd;
+ int ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleWidth;
drawLineForBoxSide(paintInfo.context, ruleLeft, ruleTop, ruleRight, ruleBottom,
style()->isLeftToRightDirection() ? BSLeft : BSRight, ruleColor, ruleStyle, 0, 0);
}
@@ -2297,8 +2339,8 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool
// For each rect, we clip to the rect, and then we adjust our coords.
IntRect colRect = columnRectAt(colInfo, i);
flipForWritingMode(colRect);
- int logicalLeftOffset = (style()->isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
- IntSize offset = style()->isHorizontalWritingMode() ? IntSize(logicalLeftOffset, currLogicalTopOffset) : IntSize(currLogicalTopOffset, logicalLeftOffset);
+ int logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
+ IntSize offset = isHorizontalWritingMode() ? IntSize(logicalLeftOffset, currLogicalTopOffset) : IntSize(currLogicalTopOffset, logicalLeftOffset);
colRect.move(tx, ty);
PaintInfo info(paintInfo);
info.rect.intersect(colRect);
@@ -2321,7 +2363,7 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool
context->restore();
}
- int blockDelta = (style()->isHorizontalWritingMode() ? colRect.height() : colRect.width());
+ int blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width());
if (style()->isFlippedBlocksWritingMode())
currLogicalTopOffset += blockDelta;
else
@@ -2510,7 +2552,7 @@ IntPoint RenderBlock::flipFloatForWritingMode(const FloatingObject* child, const
// This is similar to the ParentToChildFlippingAdjustment in RenderBox::flipForWritingMode. We have to subtract out our left/top offsets twice, since
// it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
// case.
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
return IntPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child));
return IntPoint(point.x() + width() - child->width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
}
@@ -2738,18 +2780,18 @@ static void clipOutPositionedObjects(const PaintInfo* paintInfo, const IntPoint&
static int blockDirectionOffset(RenderBlock* rootBlock, const IntSize& offsetFromRootBlock)
{
- return rootBlock->style()->isHorizontalWritingMode() ? offsetFromRootBlock.height() : offsetFromRootBlock.width();
+ return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.height() : offsetFromRootBlock.width();
}
static int inlineDirectionOffset(RenderBlock* rootBlock, const IntSize& offsetFromRootBlock)
{
- return rootBlock->style()->isHorizontalWritingMode() ? offsetFromRootBlock.width() : offsetFromRootBlock.height();
+ return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.width() : offsetFromRootBlock.height();
}
IntRect RenderBlock::logicalRectToPhysicalRect(const IntPoint& rootBlockPhysicalPosition, const IntRect& logicalRect)
{
IntRect result;
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
result = logicalRect;
else
result = IntRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width());
@@ -2846,10 +2888,10 @@ GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const IntPoint
selTop, paintInfo));
IntRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
- logicalRect.move(style()->isHorizontalWritingMode() ? offsetFromRootBlock : IntSize(offsetFromRootBlock.height(), offsetFromRootBlock.width()));
+ logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : IntSize(offsetFromRootBlock.height(), offsetFromRootBlock.width()));
IntRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
- if (!paintInfo || (style()->isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
- || (!style()->isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
+ if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
+ || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo));
lastSelectedLine = curr;
@@ -3294,12 +3336,23 @@ bool RenderBlock::positionNewFloats()
return true;
}
-bool RenderBlock::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine)
+bool RenderBlock::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, bool firstLine, int& lineLeftOffset, int& lineRightOffset)
{
bool didPosition = positionNewFloats();
- if (!didPosition || !newFloat->m_paginationStrut)
+ if (!didPosition)
return didPosition;
+
+ int blockOffset = logicalHeight();
+ if (blockOffset >= logicalTopForFloat(newFloat) && blockOffset < logicalBottomForFloat(newFloat)) {
+ if (newFloat->type() == FloatingObject::FloatLeft)
+ lineLeftOffset = logicalRightForFloat(newFloat);
+ else
+ lineRightOffset = logicalLeftForFloat(newFloat);
+ }
+ if (!newFloat->m_paginationStrut)
+ return didPosition;
+
FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
ASSERT(floatingObjectSet.last() == newFloat);
@@ -3329,8 +3382,10 @@ bool RenderBlock::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObjec
}
}
- setLogicalHeight(logicalHeight() + paginationStrut);
-
+ setLogicalHeight(blockOffset + paginationStrut);
+ lineLeftOffset = logicalLeftOffsetForLine(logicalHeight(), firstLine);
+ lineRightOffset = logicalRightOffsetForLine(logicalHeight(), firstLine);
+
return didPosition;
}
@@ -3416,6 +3471,11 @@ HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const
return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0;
}
+// FIXME: The logicalLeftOffsetForLine/logicalRightOffsetForLine functions are very slow if there are many floats
+// present. We need to add a structure to floating objects to represent "lines" of floats. Then instead of checking
+// each float individually, we'd just walk backwards through the "lines" and stop when we hit a line that is fully above
+// the vertical offset that we'd like to check. Computing the "lines" would be rather complicated, but could replace the left
+// objects and right objects count hack that is currently used here.
int RenderBlock::logicalLeftOffsetForLine(int logicalTop, int fixedOffset, bool applyTextIndent, int* heightRemaining) const
{
int left = fixedOffset;
@@ -3423,18 +3483,23 @@ int RenderBlock::logicalLeftOffsetForLine(int logicalTop, int fixedOffset, bool
if (heightRemaining)
*heightRemaining = 1;
+ // We know the list is non-empty, since we have "left" objects to search for.
+ // Therefore we can assume that begin != end, and that we can do at least one
+ // decrement.
FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
- FloatingObjectSetIterator end = floatingObjectSet.end();
- for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
+ FloatingObjectSetIterator begin = floatingObjectSet.begin();
+ FloatingObjectSetIterator it = floatingObjectSet.end();
+ do {
+ --it;
FloatingObject* r = *it;
if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop
&& r->type() == FloatingObject::FloatLeft
&& logicalRightForFloat(r) > left) {
- left = logicalRightForFloat(r);
+ left = max(left, logicalRightForFloat(r));
if (heightRemaining)
*heightRemaining = logicalBottomForFloat(r) - logicalTop;
}
- }
+ } while (it != begin);
}
if (applyTextIndent && style()->isLeftToRightDirection()) {
@@ -3454,18 +3519,24 @@ int RenderBlock::logicalRightOffsetForLine(int logicalTop, int fixedOffset, bool
if (m_floatingObjects && m_floatingObjects->hasRightObjects()) {
if (heightRemaining)
*heightRemaining = 1;
+
+ // We know the list is non-empty, since we have "right" objects to search for.
+ // Therefore we can assume that begin != end, and that we can do at least one
+ // decrement.
FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
- FloatingObjectSetIterator end = floatingObjectSet.end();
- for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
+ FloatingObjectSetIterator begin = floatingObjectSet.begin();
+ FloatingObjectSetIterator it = floatingObjectSet.end();
+ do {
+ --it;
FloatingObject* r = *it;
if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop
&& r->type() == FloatingObject::FloatRight
&& logicalLeftForFloat(r) < right) {
- right = logicalLeftForFloat(r);
+ right = min(right, logicalLeftForFloat(r));
if (heightRemaining)
*heightRemaining = logicalBottomForFloat(r) - logicalTop;
}
- }
+ } while (it != begin);
}
if (applyTextIndent && !style()->isLeftToRightDirection()) {
@@ -3663,8 +3734,8 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int logicalLeftOffset,
if (logicalBottom > logicalHeight()) {
// If the object is not in the list, we add it now.
if (!containsFloat(r->m_renderer)) {
- int leftOffset = style()->isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset;
- int topOffset = style()->isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset;
+ int leftOffset = isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset;
+ int topOffset = isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset;
FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->x() - leftOffset, r->y() - topOffset, r->width(), r->height()));
floatingObj->m_renderer = r->m_renderer;
@@ -3712,7 +3783,7 @@ void RenderBlock::addIntrudingFloats(RenderBlock* prev, int logicalLeftOffset, i
if (!prev->m_floatingObjects)
return;
- logicalLeftOffset += (style()->isHorizontalWritingMode() ? marginLeft() : marginTop());
+ logicalLeftOffset += (isHorizontalWritingMode() ? marginLeft() : marginTop());
FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
FloatingObjectSetIterator prevEnd = prevSet.end();
@@ -3720,8 +3791,8 @@ void RenderBlock::addIntrudingFloats(RenderBlock* prev, int logicalLeftOffset, i
FloatingObject* r = *prevIt;
if (logicalBottomForFloat(r) > logicalTopOffset) {
if (!m_floatingObjects || !m_floatingObjects->set().contains(r)) {
- int leftOffset = style()->isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset;
- int topOffset = style()->isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset;
+ int leftOffset = isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset;
+ int topOffset = isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset;
FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->x() - leftOffset, r->y() - topOffset, r->width(), r->height()));
@@ -3731,7 +3802,7 @@ void RenderBlock::addIntrudingFloats(RenderBlock* prev, int logicalLeftOffset, i
// into account. Only apply this code if prev is the parent, since otherwise the left margin
// will get applied twice.
if (prev != parent()) {
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
floatingObj->setX(floatingObj->x() + prev->marginLeft());
else
floatingObj->setY(floatingObj->y() + prev->marginTop());
@@ -3868,7 +3939,7 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
bool useClip = (hasControlClip() || useOverflowClip);
IntRect hitTestArea(result.rectForPoint(_x, _y));
- bool checkChildren = !useClip || (hasControlClip() ? controlClipRect(tx, ty).intersects(hitTestArea) : overflowClipRect(tx, ty).intersects(hitTestArea));
+ bool checkChildren = !useClip || (hasControlClip() ? controlClipRect(tx, ty).intersects(hitTestArea) : overflowClipRect(tx, ty, IncludeOverlayScrollbarSize).intersects(hitTestArea));
if (checkChildren) {
// Hit test descendants first.
int scrolledX = tx;
@@ -3945,7 +4016,7 @@ bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& r
int logicalLeft = logicalLeftOffsetForContent();
int currLogicalTopOffset = 0;
int i;
- bool isHorizontal = style()->isHorizontalWritingMode();
+ bool isHorizontal = isHorizontalWritingMode();
for (i = 0; i < colCount; i++) {
IntRect colRect = columnRectAt(colInfo, i);
int blockDelta = (isHorizontal ? colRect.height() : colRect.width());
@@ -4038,12 +4109,12 @@ static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBlock*
ancestor = ancestor->parent();
// If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal
- if (!ancestor || ancestor->node()->isContentEditable() == childNode->isContentEditable())
+ if (!ancestor || ancestor->node()->rendererIsEditable() == childNode->rendererIsEditable())
return child->positionForPoint(pointInChildCoordinates);
// Otherwise return before or after the child, depending on if the click was to the logical left or logical right of the child
int childMiddle = parent->logicalWidthForChild(child) / 2;
- int logicalLeft = parent->style()->isHorizontalWritingMode() ? pointInChildCoordinates.x() : pointInChildCoordinates.y();
+ int logicalLeft = parent->isHorizontalWritingMode() ? pointInChildCoordinates.x() : pointInChildCoordinates.y();
if (logicalLeft < childMiddle)
return ancestor->createVisiblePosition(childNode->nodeIndex(), DOWNSTREAM);
return ancestor->createVisiblePosition(childNode->nodeIndex() + 1, UPSTREAM);
@@ -4090,7 +4161,7 @@ VisiblePosition RenderBlock::positionForPointWithInlineChildren(const IntPoint&
// pass the box a top position that is inside it
IntPoint point(pointInLogicalContents.x(), closestBox->logicalTop());
- if (!style()->isHorizontalWritingMode())
+ if (!isHorizontalWritingMode())
point = point.transposedPoint();
if (closestBox->renderer()->isReplaced())
return positionForPointRespectingEditingBoundaries(this, toRenderBox(closestBox->renderer()), point);
@@ -4100,7 +4171,9 @@ VisiblePosition RenderBlock::positionForPointWithInlineChildren(const IntPoint&
if (lastRootBoxWithChildren) {
// We hit this case for Mac behavior when the Y coordinate is below the last box.
ASSERT(moveCaretToBoundary);
- return VisiblePosition(positionForBox(lastRootBoxWithChildren->lastLeafChild(), false), DOWNSTREAM);
+ InlineBox* logicallyLastBox;
+ if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
+ return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
}
// Can't reach this. We have a root line box, but it has no kids.
@@ -4121,8 +4194,8 @@ VisiblePosition RenderBlock::positionForPoint(const IntPoint& point)
if (isReplaced()) {
// FIXME: This seems wrong when the object's writing-mode doesn't match the line's writing-mode.
- int pointLogicalLeft = style()->isHorizontalWritingMode() ? point.x() : point.y();
- int pointLogicalTop = style()->isHorizontalWritingMode() ? point.y() : point.x();
+ int pointLogicalLeft = isHorizontalWritingMode() ? point.x() : point.y();
+ int pointLogicalTop = isHorizontalWritingMode() ? point.y() : point.x();
if (pointLogicalTop < 0 || (pointLogicalTop < logicalHeight() && pointLogicalLeft < 0))
return createVisiblePosition(caretMinOffset(), DOWNSTREAM);
@@ -4135,7 +4208,7 @@ VisiblePosition RenderBlock::positionForPoint(const IntPoint& point)
offsetForContents(contentsX, contentsY);
IntPoint pointInContents(contentsX, contentsY);
IntPoint pointInLogicalContents(pointInContents);
- if (!style()->isHorizontalWritingMode())
+ if (!isHorizontalWritingMode())
pointInLogicalContents = pointInLogicalContents.transposedPoint();
if (childrenInline())
@@ -4303,7 +4376,7 @@ IntRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const
logicalLeftOffsetForContent() + (index * (colLogicalWidth + colGap))
: logicalLeftOffsetForContent() + contentLogicalWidth() - colLogicalWidth - (index * (colLogicalWidth + colGap));
IntRect rect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight);
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
return IntRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight);
return IntRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth);
}
@@ -4370,7 +4443,7 @@ void RenderBlock::adjustPointToColumnContents(IntPoint& point) const
for (unsigned i = 0; i < colInfo->columnCount(); i++) {
// Add in half the column gap to the left and right of the rect.
IntRect colRect = columnRectAt(colInfo, i);
- if (style()->isHorizontalWritingMode()) {
+ if (isHorizontalWritingMode()) {
IntRect gapAndColumnRect(colRect.x() - halfColGap, colRect.y(), colRect.width() + colGap, colRect.height());
if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.maxX()) {
// FIXME: The clamping that follows is not completely right for right-to-left
@@ -4440,7 +4513,7 @@ void RenderBlock::adjustRectForColumns(IntRect& r) const
for (unsigned i = 0; i < colCount; i++) {
IntRect colRect = columnRectAt(colInfo, i);
IntRect repaintRect = r;
- if (style()->isHorizontalWritingMode()) {
+ if (isHorizontalWritingMode()) {
int currXOffset = colRect.x() - logicalLeft;
repaintRect.move(currXOffset, currLogicalOffset);
currLogicalOffset -= colRect.height();
@@ -4464,7 +4537,7 @@ IntPoint RenderBlock::flipForWritingModeIncludingColumns(const IntPoint& point)
ColumnInfo* colInfo = columnInfo();
int columnLogicalHeight = colInfo->columnHeight();
int expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
return IntPoint(point.x(), expandedLogicalHeight - point.y());
return IntPoint(expandedLogicalHeight - point.x(), point.y());
}
@@ -4478,7 +4551,7 @@ void RenderBlock::flipForWritingModeIncludingColumns(IntRect& rect) const
ColumnInfo* colInfo = columnInfo();
int columnLogicalHeight = colInfo->columnHeight();
int expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
rect.setY(expandedLogicalHeight - rect.maxY());
else
rect.setX(expandedLogicalHeight - rect.maxX());
@@ -4499,7 +4572,7 @@ void RenderBlock::adjustForColumns(IntSize& offset, const IntPoint& point) const
for (size_t i = 0; i < colCount; ++i) {
// Compute the edges for a given column in the block progression direction.
IntRect sliceRect = IntRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight);
- if (!style()->isHorizontalWritingMode())
+ if (!isHorizontalWritingMode())
sliceRect = sliceRect.transposedRect();
// If we have a flipped blocks writing mode, then convert the column so that it's coming from the after edge (either top or left edge).
@@ -4508,7 +4581,7 @@ void RenderBlock::adjustForColumns(IntSize& offset, const IntPoint& point) const
int logicalOffset = style()->isFlippedBlocksWritingMode() ? (colCount - 1 - i) * colLogicalHeight : i * colLogicalHeight;
// Now we're in the same coordinate space as the point. See if it is inside the rectangle.
- if (style()->isHorizontalWritingMode()) {
+ if (isHorizontalWritingMode()) {
if (point.y() >= sliceRect.y() && point.y() < sliceRect.maxY()) {
offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset);
return;
@@ -4851,7 +4924,7 @@ void RenderBlock::computeInlinePreferredLogicalWidths()
continue;
}
- if (t->style()->hasTextCombine())
+ if (t->style()->hasTextCombine() && t->isCombineText())
toRenderCombineText(t)->combineText();
// Determine if we have a breakable character. Pass in
@@ -5064,7 +5137,7 @@ bool RenderBlock::hasLineIfEmpty() const
if (!node())
return false;
- if (node()->isContentEditable() && node()->rootEditableElement() == node())
+ if (node()->rendererIsEditable() && node()->rootEditableElement() == node())
return true;
if (node()->isShadowRoot() && (node()->shadowHost()->hasTagName(inputTag)))
@@ -5159,7 +5232,7 @@ int RenderBlock::lastLineBoxBaseline() const
if (!isBlockFlow() || (isWritingModeRoot() && !isRubyRun()))
return -1;
- LineDirectionMode lineDirection = style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
+ LineDirectionMode lineDirection = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
if (childrenInline()) {
if (!firstLineBox() && hasLineIfEmpty()) {
@@ -5766,6 +5839,14 @@ IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int*
case WEBKIT_RIGHT:
alignment = alignRight;
break;
+ case TASTART:
+ if (!currentStyle->isLeftToRightDirection())
+ alignment = alignRight;
+ break;
+ case TAEND:
+ if (currentStyle->isLeftToRightDirection())
+ alignment = alignRight;
+ break;
}
int x = borderLeft() + paddingLeft();
@@ -5857,8 +5938,7 @@ void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
RenderBlock* RenderBlock::createAnonymousBlock(bool isFlexibleBox) const
{
- RefPtr<RenderStyle> newStyle = RenderStyle::create();
- newStyle->inheritFrom(style());
+ RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
RenderBlock* newBox = 0;
if (isFlexibleBox) {
@@ -5884,8 +5964,7 @@ RenderBlock* RenderBlock::createAnonymousBlockWithSameTypeAs(RenderBlock* otherA
RenderBlock* RenderBlock::createAnonymousColumnsBlock() const
{
- RefPtr<RenderStyle> newStyle = RenderStyle::create();
- newStyle->inheritFrom(style());
+ RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
newStyle->inheritColumnPropertiesFrom(style());
newStyle->setDisplay(BLOCK);
@@ -5896,8 +5975,7 @@ RenderBlock* RenderBlock::createAnonymousColumnsBlock() const
RenderBlock* RenderBlock::createAnonymousColumnSpanBlock() const
{
- RefPtr<RenderStyle> newStyle = RenderStyle::create();
- newStyle->inheritFrom(style());
+ RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
newStyle->setColumnSpan(true);
newStyle->setDisplay(BLOCK);
@@ -5915,7 +5993,7 @@ int RenderBlock::nextPageLogicalTop(int logicalOffset) const
// The logicalOffset is in our coordinate space. We can add in our pushed offset.
int pageLogicalHeight = layoutState->m_pageLogicalHeight;
IntSize delta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
- int offset = style()->isHorizontalWritingMode() ? delta.height() : delta.width();
+ int offset = isHorizontalWritingMode() ? delta.height() : delta.width();
int remainingLogicalHeight = (pageLogicalHeight - (offset + logicalOffset) % pageLogicalHeight) % pageLogicalHeight;
return logicalOffset + remainingLogicalHeight;
}
@@ -5976,7 +6054,7 @@ int RenderBlock::adjustForUnsplittableChild(RenderBox* child, int logicalOffset,
if (!pageLogicalHeight || childLogicalHeight > pageLogicalHeight)
return logicalOffset;
IntSize delta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
- int offset = style()->isHorizontalWritingMode() ? delta.height() : delta.width();
+ int offset = isHorizontalWritingMode() ? delta.height() : delta.width();
int remainingLogicalHeight = (pageLogicalHeight - (offset + logicalOffset) % pageLogicalHeight) % pageLogicalHeight;
if (remainingLogicalHeight < childLogicalHeight)
return logicalOffset + remainingLogicalHeight;
@@ -6012,7 +6090,7 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, int& d
if (!pageLogicalHeight || lineHeight > pageLogicalHeight)
return;
IntSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
- int offset = style()->isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width();
+ int offset = isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width();
int remainingLogicalHeight = pageLogicalHeight - (offset + logicalOffset) % pageLogicalHeight;
if (remainingLogicalHeight < lineHeight) {
int totalLogicalHeight = lineHeight + max(0, logicalOffset);
@@ -6034,7 +6112,7 @@ int RenderBlock::collapsedMarginBeforeForChild(RenderBox* child) const
// 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())
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
return child->collapsedMarginAfter();
// The child is perpendicular to us, which means its margins don't collapse but are on the
@@ -6051,7 +6129,7 @@ int RenderBlock::collapsedMarginAfterForChild(RenderBox* child) const
// 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())
+ if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
return child->collapsedMarginBefore();
// The child is perpendicular to us, which means its margins don't collapse but are on the
@@ -6093,21 +6171,21 @@ int RenderBlock::marginAfterForChild(RenderBoxModelObject* child) const
int RenderBlock::marginStartForChild(RenderBoxModelObject* child) const
{
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
return style()->isLeftToRightDirection() ? child->marginLeft() : child->marginRight();
return style()->isLeftToRightDirection() ? child->marginTop() : child->marginBottom();
}
int RenderBlock::marginEndForChild(RenderBoxModelObject* child) const
{
- if (style()->isHorizontalWritingMode())
+ if (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 (isHorizontalWritingMode()) {
if (style()->isLeftToRightDirection())
child->setMarginLeft(margin);
else
@@ -6122,7 +6200,7 @@ void RenderBlock::setMarginStartForChild(RenderBox* child, int margin)
void RenderBlock::setMarginEndForChild(RenderBox* child, int margin)
{
- if (style()->isHorizontalWritingMode()) {
+ if (isHorizontalWritingMode()) {
if (style()->isLeftToRightDirection())
child->setMarginRight(margin);
else
@@ -6195,7 +6273,7 @@ RenderBlock::MarginValues RenderBlock::marginValuesForChild(RenderBox* child)
beforeMargin = child->marginBefore();
afterMargin = child->marginAfter();
}
- } else if (child->style()->isHorizontalWritingMode() == style()->isHorizontalWritingMode()) {
+ } else if (child->isHorizontalWritingMode() == 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) {
diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h
index 8d054a6..74751e1 100644
--- a/Source/WebCore/rendering/RenderBlock.h
+++ b/Source/WebCore/rendering/RenderBlock.h
@@ -171,9 +171,9 @@ public:
// 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(); }
+ int logicalWidthForChild(RenderBox* child) { return isHorizontalWritingMode() ? child->width() : child->height(); }
+ int logicalHeightForChild(RenderBox* child) { return isHorizontalWritingMode() ? child->height() : child->width(); }
+ int logicalTopForChild(RenderBox* child) { return 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;
@@ -218,8 +218,8 @@ public:
virtual void scrollbarsChanged(bool /*horizontalScrollbarChanged*/, bool /*verticalScrollbarChanged*/) { };
- int logicalRightOffsetForContent() const { return style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() + availableLogicalWidth() : borderTop() + paddingTop() + availableLogicalWidth(); }
- int logicalLeftOffsetForContent() const { return style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop(); }
+ int logicalRightOffsetForContent() const { return isHorizontalWritingMode() ? borderLeft() + paddingLeft() + availableLogicalWidth() : borderTop() + paddingTop() + availableLogicalWidth(); }
+ int logicalLeftOffsetForContent() const { return isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop(); }
protected:
// These functions are only used internally to manipulate the render tree structure via remove/insert/appendChildNode.
@@ -297,7 +297,9 @@ protected:
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
virtual bool hasLineIfEmpty() const;
- bool layoutOnlyPositionedObjects();
+
+ bool simplifiedLayout();
+ void simplifiedNormalFlowLayout();
void computeOverflow(int oldClientAfterEdge, bool recomputeFloats = false);
virtual void addOverflowFromChildren();
@@ -429,35 +431,35 @@ private:
IntPoint flipFloatForWritingMode(const FloatingObject*, const IntPoint&) const;
- int logicalTopForFloat(const FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->y() : child->x(); }
- int logicalBottomForFloat(const FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->maxY() : child->maxX(); }
- int logicalLeftForFloat(const FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->x() : child->y(); }
- int logicalRightForFloat(const FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->maxX() : child->maxY(); }
- int logicalWidthForFloat(const FloatingObject* child) const { return style()->isHorizontalWritingMode() ? child->width() : child->height(); }
+ int logicalTopForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->y() : child->x(); }
+ int logicalBottomForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->maxY() : child->maxX(); }
+ int logicalLeftForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->x() : child->y(); }
+ int logicalRightForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->maxX() : child->maxY(); }
+ int logicalWidthForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->width() : child->height(); }
void setLogicalTopForFloat(FloatingObject* child, int logicalTop)
{
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
child->setY(logicalTop);
else
child->setX(logicalTop);
}
void setLogicalLeftForFloat(FloatingObject* child, int logicalLeft)
{
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
child->setX(logicalLeft);
else
child->setY(logicalLeft);
}
void setLogicalHeightForFloat(FloatingObject* child, int logicalHeight)
{
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
child->setHeight(logicalHeight);
else
child->setWidth(logicalHeight);
}
void setLogicalWidthForFloat(FloatingObject* child, int logicalWidth)
{
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
child->setWidth(logicalWidth);
else
child->setHeight(logicalWidth);
@@ -465,7 +467,7 @@ private:
int xPositionForFloatIncludingMargin(const FloatingObject* child) const
{
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
return child->x() + child->renderer()->marginLeft();
else
return child->x() + marginBeforeForChild(child->renderer());
@@ -473,31 +475,32 @@ private:
int yPositionForFloatIncludingMargin(const FloatingObject* child) const
{
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
return child->y() + marginBeforeForChild(child->renderer());
else
return child->y() + child->renderer()->marginTop();
}
// The following functions' implementations are in RenderBlockLineLayout.cpp.
+ void checkFloatsInCleanLine(RootInlineBox*, Vector<FloatWithRect>&, size_t& floatIndex, bool& encounteredNewFloat, bool& dirtiedByFloat);
RootInlineBox* determineStartPosition(bool& firstLine, bool& fullLayout, bool& previousLineBrokeCleanly,
InlineBidiResolver&, Vector<FloatWithRect>& floats, unsigned& numCleanFloats,
bool& useRepaintBounds, int& repaintTop, int& repaintBottom);
- RootInlineBox* determineEndPosition(RootInlineBox* startBox, InlineIterator& cleanLineStart,
- BidiStatus& cleanLineBidiStatus,
- int& yPos);
+ RootInlineBox* determineEndPosition(RootInlineBox* startBox, Vector<FloatWithRect>& floats, size_t floatIndex, InlineIterator& cleanLineStart,
+ BidiStatus& cleanLineBidiStatus, int& yPos);
bool matchedEndLine(const InlineBidiResolver&, const InlineIterator& endLineStart, const BidiStatus& endLineStatus,
RootInlineBox*& endLine, int& endYPos, int& repaintBottom, int& repaintTop);
void skipTrailingWhitespace(InlineIterator&, bool isLineEmpty, bool previousLineBrokeCleanly);
- int skipLeadingWhitespace(InlineBidiResolver&, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly, FloatingObject* lastFloatFromPreviousLine);
+ void skipLeadingWhitespace(InlineBidiResolver&, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly, FloatingObject* lastFloatFromPreviousLine, int& lineLeftOffset, int& lineRightOffset);
void fitBelowFloats(float widthToFit, bool firstLine, float& availableWidth);
typedef std::pair<RenderText*, LazyLineBreakIterator> LineBreakIteratorInfo;
- InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, bool& isLineEmpty, LineBreakIteratorInfo&, bool& previousLineBrokeCleanly, bool& hyphenated, EClear*, FloatingObject* lastFloatFromPreviousLine);
- RootInlineBox* constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject);
- InlineFlowBox* createLineBoxes(RenderObject*, bool firstLine);
+ InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, bool& isLineEmpty, LineBreakIteratorInfo&, bool& previousLineBrokeCleanly, bool& hyphenated,
+ EClear*, FloatingObject* lastFloatFromPreviousLine, Vector<RenderBox*>& positionedObjects);
+ RootInlineBox* constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject, RenderObject* logicallyLastRunRenderer);
+ InlineFlowBox* createLineBoxes(RenderObject*, bool firstLine, InlineBox* childBox);
- void computeInlineDirectionPositionsForLine(RootInlineBox*, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&);
+ void computeInlineDirectionPositionsForLine(RootInlineBox*, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&);
void computeBlockDirectionPositionsForLine(RootInlineBox*, BidiRun*, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&);
void deleteEllipsisLineBoxes();
void checkLinesForTextOverflow();
@@ -526,7 +529,7 @@ private:
// Positions new floats and also adjust all floats encountered on the line if any of them
// have to move to the next page/column.
- bool positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine);
+ bool positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, bool firstLine, int& lineLeftOffset, int& lineRightOffset);
void clearFloats();
int getClearDelta(RenderBox* child, int yPos);
diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp
index d1fce88..3a0f016 100644
--- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp
+++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp
@@ -95,7 +95,7 @@ static void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator&
// Check to see if our last midpoint is a start point beyond the line break. If so,
// shave it off the list, and shave off a trailing space if the previous end point doesn't
// preserve whitespace.
- if (lBreak.obj && lineMidpointState.numMidpoints && !(lineMidpointState.numMidpoints % 2)) {
+ if (lBreak.m_obj && lineMidpointState.numMidpoints && !(lineMidpointState.numMidpoints % 2)) {
InlineIterator* midpoints = lineMidpointState.midpoints.data();
InlineIterator& endpoint = midpoints[lineMidpointState.numMidpoints - 2];
const InlineIterator& startpoint = midpoints[lineMidpointState.numMidpoints - 1];
@@ -105,8 +105,8 @@ static void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator&
if (currpoint == lBreak) {
// We hit the line break before the start point. Shave off the start point.
lineMidpointState.numMidpoints--;
- if (endpoint.obj->style()->collapseWhiteSpace())
- endpoint.pos--;
+ if (endpoint.m_obj->style()->collapseWhiteSpace())
+ endpoint.m_pos--;
}
}
}
@@ -132,31 +132,31 @@ void RenderBlock::appendRunsForObject(int start, int end, RenderObject* obj, Inl
if (haveNextMidpoint)
nextMidpoint = lineMidpointState.midpoints[lineMidpointState.currentMidpoint];
if (lineMidpointState.betweenMidpoints) {
- if (!(haveNextMidpoint && nextMidpoint.obj == obj))
+ if (!(haveNextMidpoint && nextMidpoint.m_obj == obj))
return;
// This is a new start point. Stop ignoring objects and
// adjust our start.
lineMidpointState.betweenMidpoints = false;
- start = nextMidpoint.pos;
+ start = nextMidpoint.m_pos;
lineMidpointState.currentMidpoint++;
if (start < end)
return appendRunsForObject(start, end, obj, resolver);
} else {
- if (!haveNextMidpoint || (obj != nextMidpoint.obj)) {
+ if (!haveNextMidpoint || (obj != nextMidpoint.m_obj)) {
resolver.addRun(new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir()));
return;
}
// An end midpoint has been encountered within our object. We
// need to go ahead and append a run with our endpoint.
- if (static_cast<int>(nextMidpoint.pos + 1) <= end) {
+ if (static_cast<int>(nextMidpoint.m_pos + 1) <= end) {
lineMidpointState.betweenMidpoints = true;
lineMidpointState.currentMidpoint++;
- if (nextMidpoint.pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
- if (static_cast<int>(nextMidpoint.pos + 1) > start)
+ if (nextMidpoint.m_pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
+ if (static_cast<int>(nextMidpoint.m_pos + 1) > start)
resolver.addRun(new (obj->renderArena())
- BidiRun(start, nextMidpoint.pos + 1, obj, resolver.context(), resolver.dir()));
- return appendRunsForObject(nextMidpoint.pos + 1, end, obj, resolver);
+ BidiRun(start, nextMidpoint.m_pos + 1, obj, resolver.context(), resolver.dir()));
+ return appendRunsForObject(nextMidpoint.m_pos + 1, end, obj, resolver);
}
} else
resolver.addRun(new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir()));
@@ -203,14 +203,14 @@ static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox)
return false;
}
-InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine)
+InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine, InlineBox* childBox)
{
// See if we have an unconstructed line box for this object that is also
// the last item on the line.
unsigned lineDepth = 1;
- InlineFlowBox* childBox = 0;
InlineFlowBox* parentBox = 0;
InlineFlowBox* result = 0;
+ bool hasDefaultLineBoxContain = style()->lineBoxContain() == RenderStyle::initialLineBoxContain();
do {
ASSERT(obj->isRenderInline() || obj == this);
@@ -230,7 +230,9 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine)
ASSERT(newBox->isInlineFlowBox());
parentBox = static_cast<InlineFlowBox*>(newBox);
parentBox->setFirstLineStyleBit(firstLine);
- parentBox->setIsHorizontal(style()->isHorizontalWritingMode());
+ parentBox->setIsHorizontal(isHorizontalWritingMode());
+ if (!hasDefaultLineBoxContain)
+ parentBox->clearDescendantsHaveSameLineHeightAndBaseline();
constructedNewBox = true;
}
@@ -257,7 +259,7 @@ InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, bool firstLine)
return result;
}
-RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject)
+RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject, RenderObject* logicallyLastRunRenderer)
{
ASSERT(firstRun);
@@ -284,10 +286,11 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun,
// run's inline box.
if (!parentBox || parentBox->renderer() != r->m_object->parent())
// Create new inline boxes all the way back to the appropriate insertion point.
- parentBox = createLineBoxes(r->m_object->parent(), firstLine);
-
- // Append the inline box to this line.
- parentBox->addToLine(box);
+ parentBox = createLineBoxes(r->m_object->parent(), firstLine, box);
+ else {
+ // Append the inline box to this line.
+ parentBox->addToLine(box);
+ }
bool visuallyOrdered = r->m_object->style()->visuallyOrdered();
box->setBidiLevel(r->level());
@@ -315,7 +318,7 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun,
// paint borders/margins/padding. This knowledge will ultimately be used when
// we determine the horizontal positions and widths of all the inline boxes on
// the line.
- lastLineBox()->determineSpacingForFlowBoxes(lastLine, endObject);
+ lastLineBox()->determineSpacingForFlowBoxes(lastLine, endObject, logicallyLastRunRenderer);
// Now mark the line boxes as being constructed.
lastLineBox()->setConstructed();
@@ -333,7 +336,60 @@ ETextAlign RenderBlock::textAlignmentForLine(bool endsWithSoftBreak) const
return alignment;
}
-void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap& textBoxDataMap)
+static void updateLogicalWidthForLeftAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
+{
+ // 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 (isLeftToRightDirection) {
+ if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
+ trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
+ return;
+ }
+
+ if (trailingSpaceRun)
+ trailingSpaceRun->m_box->setLogicalWidth(0);
+ else if (totalLogicalWidth > availableLogicalWidth)
+ logicalLeft -= (totalLogicalWidth - availableLogicalWidth);
+}
+
+static void updateLogicalWidthForRightAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
+{
+ // 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 (isLeftToRightDirection) {
+ if (trailingSpaceRun) {
+ totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
+ trailingSpaceRun->m_box->setLogicalWidth(0);
+ }
+ if (totalLogicalWidth < availableLogicalWidth)
+ logicalLeft += availableLogicalWidth - totalLogicalWidth;
+ return;
+ }
+
+ if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) {
+ trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
+ totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
+ } else
+ logicalLeft += availableLogicalWidth - totalLogicalWidth;
+}
+
+static void updateLogicalWidthForCenterAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
+{
+ float trailingSpaceWidth = 0;
+ if (trailingSpaceRun) {
+ totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
+ trailingSpaceWidth = min(trailingSpaceRun->m_box->logicalWidth(), (availableLogicalWidth - totalLogicalWidth + 1) / 2);
+ trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceWidth));
+ }
+ if (isLeftToRightDirection)
+ logicalLeft += max<float>((availableLogicalWidth - totalLogicalWidth) / 2, 0);
+ else
+ logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLogicalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2 - trailingSpaceWidth;
+}
+
+void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd,
+ GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache)
{
ETextAlign textAlign = textAlignmentForLine(!reachedEnd && !lineBox->endsWithBreak());
float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), firstLine);
@@ -354,6 +410,8 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
RenderText* rt = toRenderText(r->m_object);
if (textAlign == JUSTIFY && r != trailingSpaceRun) {
+ if (!isAfterExpansion)
+ static_cast<InlineTextBox*>(r->m_box)->setCanHaveLeadingExpansion(true);
unsigned opportunitiesInRun = Font::expansionOpportunityCount(rt->characters() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion);
expansionOpportunities.append(opportunitiesInRun);
expansionOpportunityCount += opportunitiesInRun;
@@ -366,6 +424,21 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
}
HashSet<const SimpleFontData*> fallbackFonts;
GlyphOverflow glyphOverflow;
+
+ // Always compute glyph overflow if the block's line-box-contain value is "glyphs".
+ if (lineBox->fitsToGlyphs()) {
+ // If we don't stick out of the root line's font box, then don't bother computing our glyph overflow. This optimization
+ // will keep us from computing glyph bounds in nearly all cases.
+ bool includeRootLine = lineBox->includesRootLineBoxFontOrLeading();
+ int baselineShift = lineBox->verticalPositionForBox(r->m_box, verticalPositionCache);
+ int rootDescent = includeRootLine ? lineBox->renderer()->style(firstLine)->font().fontMetrics().descent() : 0;
+ int rootAscent = includeRootLine ? lineBox->renderer()->style(firstLine)->font().fontMetrics().ascent() : 0;
+ int boxAscent = rt->style(firstLine)->font().fontMetrics().ascent() - baselineShift;
+ int boxDescent = rt->style(firstLine)->font().fontMetrics().descent() + baselineShift;
+ if (boxAscent > rootDescent || boxDescent > rootAscent)
+ glyphOverflow.computeBounds = true;
+ }
+
int hyphenWidth = 0;
if (static_cast<InlineTextBox*>(r->m_box)->hasHyphen()) {
const AtomicString& hyphenString = rt->style()->hyphenString();
@@ -377,6 +450,7 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(static_cast<InlineTextBox*>(r->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first;
ASSERT(it->second.first.isEmpty());
copyToVector(fallbackFonts, it->second.first);
+ r->m_box->parent()->clearDescendantsHaveSameLineHeightAndBaseline();
}
if ((glyphOverflow.top || glyphOverflow.bottom || glyphOverflow.left || glyphOverflow.right)) {
ASSERT(r->m_box->isText());
@@ -408,17 +482,7 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
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()->isLeftToRightDirection()) {
- if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
- trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
- } else {
- if (trailingSpaceRun)
- trailingSpaceRun->m_box->setLogicalWidth(0);
- else if (totalLogicalWidth > availableLogicalWidth)
- logicalLeft -= (totalLogicalWidth - availableLogicalWidth);
- }
+ updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
break;
case JUSTIFY:
adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft, availableLogicalWidth);
@@ -439,40 +503,27 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox,
}
case RIGHT:
case WEBKIT_RIGHT:
- // 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()->isLeftToRightDirection()) {
- if (trailingSpaceRun) {
- totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
- trailingSpaceRun->m_box->setLogicalWidth(0);
- }
- if (totalLogicalWidth < availableLogicalWidth)
- logicalLeft += availableLogicalWidth - totalLogicalWidth;
- } else {
- if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) {
- trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
- totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
- } else
- logicalLeft += availableLogicalWidth - totalLogicalWidth;
- }
+ updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
break;
case CENTER:
case WEBKIT_CENTER:
- float trailingSpaceWidth = 0;
- if (trailingSpaceRun) {
- totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
- trailingSpaceWidth = min(trailingSpaceRun->m_box->logicalWidth(), (availableLogicalWidth - totalLogicalWidth + 1) / 2);
- trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceWidth));
- }
+ updateLogicalWidthForCenterAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
+ break;
+ case TASTART:
if (style()->isLeftToRightDirection())
- logicalLeft += max<float>((availableLogicalWidth - totalLogicalWidth) / 2, 0);
+ updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
else
- logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLogicalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2 - trailingSpaceWidth;
+ updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
+ break;
+ case TAEND:
+ if (style()->isLeftToRightDirection())
+ updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
+ else
+ updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
break;
}
- if (expansionOpportunityCount) {
+ if (expansionOpportunityCount && availableLogicalWidth > totalLogicalWidth) {
size_t i = 0;
for (BidiRun* r = firstRun; r; r = r->next()) {
if (!r->m_box || r == trailingSpaceRun)
@@ -543,6 +594,49 @@ static inline bool isCollapsibleSpace(UChar character, RenderText* renderer)
return false;
}
+
+static void setStaticPositions(RenderBlock* block, RenderBox* child)
+{
+ // FIXME: The math here is actually not really right. It's a best-guess approximation that
+ // will work for the common cases
+ RenderObject* containerBlock = child->container();
+ int blockHeight = block->logicalHeight();
+ if (containerBlock->isRenderInline()) {
+ // A relative positioned inline encloses us. In this case, we also have to determine our
+ // position as though we were an inline. Set |staticInlinePosition| and |staticBlockPosition| on the relative positioned
+ // inline so that we can obtain the value later.
+ toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block->startOffsetForLine(blockHeight, false));
+ toRenderInline(containerBlock)->layer()->setStaticBlockPosition(blockHeight);
+ }
+
+ if (child->style()->isOriginalDisplayInlineType())
+ child->layer()->setStaticInlinePosition(block->startOffsetForLine(blockHeight, false));
+ else
+ child->layer()->setStaticInlinePosition(block->borderAndPaddingStart());
+ child->layer()->setStaticBlockPosition(blockHeight);
+}
+
+static bool reachedEndOfTextRenderer(InlineBidiResolver& resolver)
+{
+ BidiRun* run = resolver.logicallyLastRun();
+ if (!run)
+ return true;
+ unsigned int pos = run->stop();
+ RenderObject* r = run->m_object;
+ if (!r->isText() || r->isBR())
+ return false;
+ RenderText* renderText = toRenderText(r);
+ if (pos >= renderText->textLength())
+ return true;
+
+ while (isASCIISpace(renderText->characters()[pos])) {
+ pos++;
+ if (pos >= renderText->textLength())
+ return true;
+ }
+ return false;
+}
+
void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogicalTop, int& repaintLogicalBottom)
{
bool useRepaintBounds = false;
@@ -748,7 +842,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica
BidiStatus cleanLineBidiStatus;
int endLineLogicalTop = 0;
RootInlineBox* endLine = (fullLayout || !startLine) ?
- 0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, endLineLogicalTop);
+ 0 : determineEndPosition(startLine, floats, floatIndex, cleanLineStart, cleanLineBidiStatus, endLineLogicalTop);
if (startLine) {
if (!useRepaintBounds) {
@@ -806,10 +900,11 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica
EClear clear = CNONE;
bool hyphenated;
+ Vector<RenderBox*> positionedObjects;
InlineIterator oldEnd = end;
FloatingObject* lastFloatFromPreviousLine = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0;
- end = findNextLineBreak(resolver, firstLine, isLineEmpty, lineBreakIteratorInfo, previousLineBrokeCleanly, hyphenated, &clear, lastFloatFromPreviousLine);
+ end = findNextLineBreak(resolver, firstLine, isLineEmpty, lineBreakIteratorInfo, previousLineBrokeCleanly, hyphenated, &clear, lastFloatFromPreviousLine, positionedObjects);
if (resolver.position().atEnd()) {
resolver.deleteRuns();
checkForFloatsFromLastLine = true;
@@ -817,7 +912,10 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica
}
ASSERT(end != resolver.position());
- if (!isLineEmpty) {
+ if (isLineEmpty) {
+ if (lastRootBox())
+ lastRootBox()->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status());
+ } else {
VisualDirectionOverride override = (style()->visuallyOrdered() ? (style()->direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride);
resolver.createBidiRunsForLine(end, override, previousLineBrokeCleanly);
ASSERT(resolver.position() == end);
@@ -879,7 +977,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica
if (resolver.runCount()) {
if (hyphenated)
resolver.logicallyLastRun()->m_hasHyphen = true;
- lineBox = constructLine(resolver.runCount(), resolver.firstRun(), resolver.lastRun(), firstLine, !end.obj, end.obj && !end.pos ? end.obj : 0);
+ bool lastLine = end.m_obj && end.m_obj->isText() ? reachedEndOfTextRenderer(resolver) : !end.m_obj;
+ lineBox = constructLine(resolver.runCount(), resolver.firstRun(), resolver.lastRun(), firstLine, lastLine, end.m_obj && !end.m_pos ? end.m_obj : 0, resolver.logicallyLastRun()->m_object);
if (lineBox) {
lineBox->setEndsWithBreak(previousLineBrokeCleanly);
@@ -890,10 +989,10 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica
#endif
GlyphOverflowAndFallbackFontsMap textBoxDataMap;
-
+
// Now we position all of our text runs horizontally.
if (!isSVGRootInlineBox)
- computeInlineDirectionPositionsForLine(lineBox, firstLine, resolver.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap);
+ computeInlineDirectionPositionsForLine(lineBox, firstLine, resolver.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache);
// Now position our text runs vertically.
computeBlockDirectionPositionsForLine(lineBox, resolver.firstRun(), textBoxDataMap, verticalPositionCache);
@@ -924,7 +1023,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica
resolver.deleteRuns();
if (lineBox) {
- lineBox->setLineBreakInfo(end.obj, end.pos, resolver.status());
+ lineBox->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status());
if (useRepaintBounds) {
repaintLogicalTop = min(repaintLogicalTop, beforeSideVisualOverflowForLine(lineBox));
repaintLogicalBottom = max(repaintLogicalBottom, afterSideVisualOverflowForLine(lineBox));
@@ -954,6 +1053,9 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica
}
}
+ for (size_t i = 0; i < positionedObjects.size(); ++i)
+ setStaticPositions(this, positionedObjects[i]);
+
firstLine = false;
newLine(clear);
}
@@ -1081,7 +1183,7 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica
setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
if (!firstLineBox() && hasLineIfEmpty())
- setLogicalHeight(logicalHeight() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
+ setLogicalHeight(logicalHeight() + lineHeight(true, 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.
@@ -1089,6 +1191,35 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintLogica
checkLinesForTextOverflow();
}
+void RenderBlock::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWithRect>& floats, size_t& floatIndex, bool& encounteredNewFloat, bool& dirtiedByFloat)
+{
+ Vector<RenderBox*>* cleanLineFloats = line->floatsPtr();
+ if (!cleanLineFloats)
+ return;
+
+ Vector<RenderBox*>::iterator end = cleanLineFloats->end();
+ for (Vector<RenderBox*>::iterator it = cleanLineFloats->begin(); it != end; ++it) {
+ RenderBox* floatingBox = *it;
+ floatingBox->layoutIfNeeded();
+ IntSize newSize(floatingBox->width() + floatingBox->marginLeft() + floatingBox->marginRight(), floatingBox->height() + floatingBox->marginTop() + floatingBox->marginBottom());
+ ASSERT(floatIndex < floats.size());
+ if (floats[floatIndex].object != floatingBox) {
+ encounteredNewFloat = true;
+ return;
+ }
+ if (floats[floatIndex].rect.size() != newSize) {
+ int floatTop = isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x();
+ int floatHeight = isHorizontalWritingMode() ? max(floats[floatIndex].rect.height(), newSize.height())
+ : max(floats[floatIndex].rect.width(), newSize.width());
+ line->markDirty();
+ markLinesDirtyInBlockRange(line->blockLogicalHeight(), floatTop + floatHeight, line);
+ floats[floatIndex].rect.setSize(newSize);
+ dirtiedByFloat = true;
+ }
+ floatIndex++;
+ }
+}
+
RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLayout, bool& previousLineBrokeCleanly,
InlineBidiResolver& resolver, Vector<FloatWithRect>& floats, unsigned& numCleanFloats,
bool& useRepaintBounds, int& repaintLogicalTop, int& repaintLogicalBottom)
@@ -1121,32 +1252,9 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa
curr->adjustBlockDirectionPosition(paginationDelta);
}
}
-
- if (Vector<RenderBox*>* cleanLineFloats = curr->floatsPtr()) {
- Vector<RenderBox*>::iterator end = cleanLineFloats->end();
- for (Vector<RenderBox*>::iterator o = cleanLineFloats->begin(); o != end; ++o) {
- RenderBox* f = *o;
- f->layoutIfNeeded();
- IntSize newSize(f->width() + f->marginLeft() + f->marginRight(), f->height() + f->marginTop() + f->marginBottom());
- ASSERT(floatIndex < floats.size());
- if (floats[floatIndex].object != f) {
- // A new float has been inserted before this line or before its last known float.
- // Just do a full layout.
- fullLayout = true;
- break;
- }
- if (floats[floatIndex].rect.size() != newSize) {
- 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();
- markLinesDirtyInBlockRange(curr->blockLogicalHeight(), floatTop + floatHeight, curr);
- floats[floatIndex].rect.setSize(newSize);
- dirtiedByFloat = true;
- }
- floatIndex++;
- }
- }
+
+ // If a new float has been inserted before this line or before its last known float,just do a full layout.
+ checkFloatsInCleanLine(curr, floats, floatIndex, fullLayout, dirtiedByFloat);
if (dirtiedByFloat || fullLayout)
break;
}
@@ -1220,17 +1328,12 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa
pos = last->lineBreakPos();
resolver.setStatus(last->lineBreakBidiStatus());
} else {
- bool ltr = style()->isLeftToRightDirection()
- #if ENABLE(SVG)
- || (style()->unicodeBidi() == UBNormal && isSVGText())
- #endif
- ;
-
+ bool ltr = style()->isLeftToRightDirection();
Direction direction = ltr ? LeftToRight : RightToLeft;
resolver.setLastStrongDir(direction);
resolver.setLastDir(direction);
resolver.setEorDir(direction);
- resolver.setContext(BidiContext::create(ltr ? 0 : 1, direction, style()->unicodeBidi() == Override));
+ resolver.setContext(BidiContext::create(ltr ? 0 : 1, direction, style()->unicodeBidi() == Override, FromStyleOrDOM));
startObj = bidiFirst(this, &resolver);
}
@@ -1240,23 +1343,29 @@ RootInlineBox* RenderBlock::determineStartPosition(bool& firstLine, bool& fullLa
return curr;
}
-RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus, int& logicalTop)
+RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, Vector<FloatWithRect>& floats, size_t floatIndex, InlineIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus, int& logicalTop)
{
RootInlineBox* last = 0;
- if (!startLine)
- last = 0;
- else {
- for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) {
- if (curr->isDirty())
- last = 0;
- else if (!last)
- last = curr;
+ for (RootInlineBox* curr = startLine->nextRootBox(); curr; curr = curr->nextRootBox()) {
+ if (!curr->isDirty()) {
+ bool encounteredNewFloat = false;
+ bool dirtiedByFloat = false;
+ checkFloatsInCleanLine(curr, floats, floatIndex, encounteredNewFloat, dirtiedByFloat);
+ if (encounteredNewFloat)
+ return 0;
}
+ if (curr->isDirty())
+ last = 0;
+ else if (!last)
+ last = curr;
}
if (!last)
return 0;
+ // At this point, |last| is the first line in a run of clean lines that ends with the last line
+ // in the block.
+
RootInlineBox* prev = last->prevRootBox();
cleanLineStart = InlineIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
cleanLineBidiStatus = prev->lineBreakBidiStatus();
@@ -1305,7 +1414,7 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin
static int numLines = 8; // The # of lines we're willing to match against.
RootInlineBox* line = endLine;
for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
- if (line->lineBreakObj() == resolver.position().obj && line->lineBreakPos() == resolver.position().pos) {
+ if (line->lineBreakObj() == resolver.position().m_obj && line->lineBreakPos() == resolver.position().m_pos) {
// We have a match.
if (line->lineBreakBidiStatus() != resolver.status())
return false; // ...but the bidi state doesn't match.
@@ -1356,7 +1465,7 @@ bool RenderBlock::matchedEndLine(const InlineBidiResolver& resolver, const Inlin
static inline bool skipNonBreakingSpace(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly)
{
- if (it.obj->style()->nbspMode() != SPACE || it.current() != noBreakSpace)
+ if (it.m_obj->style()->nbspMode() != SPACE || it.current() != noBreakSpace)
return false;
// FIXME: This is bad. It makes nbsp inconsistent with space and won't work correctly
@@ -1395,17 +1504,17 @@ static bool inlineFlowRequiresLineBox(RenderInline* flow)
bool RenderBlock::requiresLineBox(const InlineIterator& it, bool isLineEmpty, bool previousLineBrokeCleanly)
{
- if (it.obj->isFloatingOrPositioned())
+ if (it.m_obj->isFloatingOrPositioned())
return false;
- if (it.obj->isRenderInline() && !inlineFlowRequiresLineBox(toRenderInline(it.obj)))
+ if (it.m_obj->isRenderInline() && !inlineFlowRequiresLineBox(toRenderInline(it.m_obj)))
return false;
- if (!shouldCollapseWhiteSpace(it.obj->style(), isLineEmpty, previousLineBrokeCleanly) || it.obj->isBR())
+ if (!shouldCollapseWhiteSpace(it.m_obj->style(), isLineEmpty, previousLineBrokeCleanly) || it.m_obj->isBR())
return true;
UChar current = it.current();
- return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || shouldPreserveNewline(it.obj))
+ return current != ' ' && current != '\t' && current != softHyphen && (current != '\n' || shouldPreserveNewline(it.m_obj))
&& !skipNonBreakingSpace(it, isLineEmpty, previousLineBrokeCleanly);
}
@@ -1420,34 +1529,6 @@ bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj, bool
return !it.atEnd();
}
-static void setStaticPositions(RenderBlock* block, RenderBox* child)
-{
- // FIXME: The math here is actually not really right. It's a best-guess approximation that
- // will work for the common cases
- RenderObject* containerBlock = child->container();
- if (containerBlock->isRenderInline()) {
- // A relative positioned inline encloses us. In this case, we also have to determine our
- // position as though we were an inline. Set |staticInlinePosition| and |staticBlockPosition| on the relative positioned
- // inline so that we can obtain the value later.
- toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block->startOffsetForLine(block->logicalHeight(), false));
- toRenderInline(containerBlock)->layer()->setStaticBlockPosition(block->logicalHeight());
- }
-
- bool isHorizontal = block->style()->isHorizontalWritingMode();
- bool hasStaticInlinePosition = child->style()->hasStaticInlinePosition(isHorizontal);
- bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
-
- if (hasStaticInlinePosition) {
- if (child->style()->isOriginalDisplayInlineType())
- child->layer()->setStaticInlinePosition(block->startOffsetForLine(block->logicalHeight(), false));
- else
- child->layer()->setStaticInlinePosition(block->borderAndPaddingStart());
- }
-
- if (hasStaticBlockPosition)
- child->layer()->setStaticBlockPosition(block->logicalHeight());
-}
-
// FIXME: The entire concept of the skipTrailingWhitespace function is flawed, since we really need to be building
// line boxes even for containers that may ultimately collapse away. Otherwise we'll never get positioned
// elements quite right. In other words, we need to build this function's work into the normal line
@@ -1457,7 +1538,7 @@ static void setStaticPositions(RenderBlock* block, RenderBox* child)
void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator, bool isLineEmpty, bool previousLineBrokeCleanly)
{
while (!iterator.atEnd() && !requiresLineBox(iterator, isLineEmpty, previousLineBrokeCleanly)) {
- RenderObject* object = iterator.obj;
+ RenderObject* object = iterator.m_obj;
if (object->isFloating()) {
insertFloatingObject(toRenderBox(object));
} else if (object->isPositioned())
@@ -1466,21 +1547,18 @@ void RenderBlock::skipTrailingWhitespace(InlineIterator& iterator, bool isLineEm
}
}
-int RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly,
- FloatingObject* lastFloatFromPreviousLine)
+void RenderBlock::skipLeadingWhitespace(InlineBidiResolver& resolver, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly,
+ FloatingObject* lastFloatFromPreviousLine, int& lineLeftOffset, int& lineRightOffset)
{
- 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(logicalHeight(), firstLine);
- } else if (object->isPositioned())
+ RenderObject* object = resolver.position().m_obj;
+ if (object->isFloating())
+ positionNewFloatOnLine(insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine, firstLine, lineLeftOffset, lineRightOffset);
+ else if (object->isPositioned())
setStaticPositions(this, toRenderBox(object));
resolver.increment();
}
resolver.commitExplicitEmbedding();
- return availableWidth;
}
// This is currently just used for list markers and inline flows that have line boxes. Neither should
@@ -1560,7 +1638,7 @@ static void tryHyphenating(RenderText* text, const Font& font, const AtomicStrin
// FIXME: The following assumes that the character at lastSpace is a space (and therefore should not factor
// into hyphenate-limit-before) unless lastSpace is 0. This is wrong in the rare case of hyphenating
// the first word in a text node which has leading whitespace.
- if (prefixLength - (lastSpace ? 1 : 0) < static_cast<unsigned>(minimumPrefixLength))
+ if (!prefixLength || prefixLength - (lastSpace ? 1 : 0) < static_cast<unsigned>(minimumPrefixLength))
return;
ASSERT(pos - lastSpace - prefixLength >= static_cast<unsigned>(minimumSuffixLength));
@@ -1572,22 +1650,25 @@ static void tryHyphenating(RenderText* text, const Font& font, const AtomicStrin
UNUSED_PARAM(isFixedPitch);
#endif
- lineBreak.obj = text;
- lineBreak.pos = lastSpace + prefixLength;
- lineBreak.nextBreakablePosition = nextBreakable;
+ lineBreak.moveTo(text, lastSpace + prefixLength, nextBreakable);
hyphenated = true;
}
InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool firstLine, bool& isLineEmpty, LineBreakIteratorInfo& lineBreakIteratorInfo, bool& previousLineBrokeCleanly,
- bool& hyphenated, EClear* clear, FloatingObject* lastFloatFromPreviousLine)
+ bool& hyphenated, EClear* clear, FloatingObject* lastFloatFromPreviousLine, Vector<RenderBox*>& positionedBoxes)
{
- ASSERT(resolver.position().block == this);
+ ASSERT(resolver.position().m_block == this);
- bool appliedStartWidth = resolver.position().pos > 0;
+ bool appliedStartWidth = resolver.position().m_pos > 0;
LineMidpointState& lineMidpointState = resolver.midpointState();
- float width = skipLeadingWhitespace(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, lastFloatFromPreviousLine);
+ int blockOffset = logicalHeight();
+ int lineLeftOffset = logicalLeftOffsetForLine(blockOffset, firstLine);
+ int lineRightOffset = logicalRightOffsetForLine(blockOffset, firstLine);
+
+ skipLeadingWhitespace(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, lastFloatFromPreviousLine, lineLeftOffset, lineRightOffset);
+ float width = max(0, lineRightOffset - lineLeftOffset);
float w = 0;
float tmpW = 0;
@@ -1605,13 +1686,16 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
bool currentCharacterIsSpace = false;
bool currentCharacterIsWS = false;
RenderObject* trailingSpaceObject = 0;
+ Vector<RenderBox*, 4> trailingPositionedBoxes;
InlineIterator lBreak = resolver.position();
- RenderObject* o = resolver.position().obj;
+ // FIXME: It is error-prone to split the position object out like this.
+ // Teach this code to work with objects instead of this split tuple.
+ RenderObject* o = resolver.position().m_obj;
RenderObject* last = o;
- unsigned pos = resolver.position().pos;
- int nextBreakable = resolver.position().nextBreakablePosition;
+ unsigned pos = resolver.position().m_pos;
+ int nextBreakable = resolver.position().m_nextBreakablePosition;
bool atStart = true;
bool prevLineBrokeCleanly = previousLineBrokeCleanly;
@@ -1646,9 +1730,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
if (o->isBR()) {
if (w + tmpW <= width) {
- lBreak.obj = o;
- lBreak.pos = 0;
- lBreak.nextBreakablePosition = -1;
+ lBreak.moveToStartOf(o);
lBreak.increment();
// A <br> always breaks a line, so don't let the line be collapsed
@@ -1676,8 +1758,12 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
// If it does, position it now, otherwise, position
// it after moving to next line (in newLine() func)
if (floatsFitOnLine && logicalWidthForFloat(f) + w + tmpW <= width) {
- positionNewFloatOnLine(f, lastFloatFromPreviousLine);
- width = availableLogicalWidthForLine(logicalHeight(), firstLine);
+ positionNewFloatOnLine(f, lastFloatFromPreviousLine, firstLine, lineLeftOffset, lineRightOffset);
+ width = max(0, lineRightOffset - lineLeftOffset);
+ if (lBreak.m_obj == o) {
+ ASSERT(!lBreak.m_pos);
+ lBreak.increment();
+ }
} else
floatsFitOnLine = false;
} else if (o->isPositioned()) {
@@ -1685,37 +1771,27 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
// go ahead and determine our static inline position now.
RenderBox* box = toRenderBox(o);
bool isInlineType = box->style()->isOriginalDisplayInlineType();
- bool needToSetStaticInlinePosition = box->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode());
- if (needToSetStaticInlinePosition && !isInlineType) {
+ if (!isInlineType)
box->layer()->setStaticInlinePosition(borderAndPaddingStart());
- needToSetStaticInlinePosition = false;
- }
-
- // If our original display was an INLINE type, then we can go ahead
- // and determine our static y position now.
- bool needToSetStaticBlockPosition = box->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode());
- if (needToSetStaticBlockPosition && isInlineType) {
+ else {
+ // If our original display was an INLINE type, then we can go ahead
+ // and determine our static y position now.
box->layer()->setStaticBlockPosition(logicalHeight());
- needToSetStaticBlockPosition = false;
}
- bool needToCreateLineBox = needToSetStaticInlinePosition || needToSetStaticBlockPosition;
- RenderObject* c = o->container();
- if (c->isRenderInline() && (!needToSetStaticInlinePosition || !needToSetStaticBlockPosition))
- needToCreateLineBox = true;
-
// If we're ignoring spaces, we have to stop and include this object and
// then start ignoring spaces again.
- if (needToCreateLineBox) {
- trailingSpaceObject = 0;
- ignoreStart.obj = o;
- ignoreStart.pos = 0;
+ if (isInlineType || o->container()->isRenderInline()) {
if (ignoringSpaces) {
+ ignoreStart.m_obj = o;
+ ignoreStart.m_pos = 0;
addMidpoint(lineMidpointState, ignoreStart); // Stop ignoring spaces.
addMidpoint(lineMidpointState, ignoreStart); // Start ignoring again.
}
-
- }
+ if (trailingSpaceObject)
+ trailingPositionedBoxes.append(box);
+ } else
+ positionedBoxes.append(box);
}
} else if (o->isRenderInline()) {
// Right now, we should only encounter empty inlines here.
@@ -1731,9 +1807,10 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
isLineEmpty = false;
if (ignoringSpaces) {
trailingSpaceObject = 0;
+ trailingPositionedBoxes.clear();
addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); // Stop ignoring spaces.
addMidpoint(lineMidpointState, InlineIterator(0, o, 0)); // Start ignoring again.
- } else if (style()->collapseWhiteSpace() && resolver.position().obj == o
+ } else if (style()->collapseWhiteSpace() && resolver.position().m_obj == o
&& shouldSkipWhitespaceAfterStartObject(this, o, lineMidpointState)) {
// Like with list markers, we start ignoring spaces to make sure that any
// additional spaces we see will be discarded.
@@ -1752,9 +1829,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
if ((autoWrap || RenderStyle::autoWrap(lastWS)) && (!o->isImage() || allowImagesToBreak)) {
w += tmpW;
tmpW = 0;
- lBreak.obj = o;
- lBreak.pos = 0;
- lBreak.nextBreakablePosition = -1;
+ lBreak.moveToStartOf(o);
}
if (ignoringSpaces)
@@ -1765,6 +1840,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
currentCharacterIsSpace = false;
currentCharacterIsWS = false;
trailingSpaceObject = 0;
+ trailingPositionedBoxes.clear();
// Optimize for a common case. If we can't find whitespace after the list
// item, then this is all moot.
@@ -1792,7 +1868,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
#endif
RenderStyle* style = t->style(firstLine);
- if (style->hasTextCombine())
+ if (style->hasTextCombine() && o->isCombineText())
toRenderCombineText(o)->combineText();
int strlen = t->textLength();
@@ -1824,9 +1900,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
if (t->isWordBreak()) {
w += tmpW;
tmpW = 0;
- lBreak.obj = o;
- lBreak.pos = 0;
- lBreak.nextBreakablePosition = -1;
+ lBreak.moveToStartOf(o);
ASSERT(!len);
}
@@ -1922,9 +1996,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
// additional whitespace.
if (w + tmpW + charWidth > width) {
lineWasTooWide = true;
- lBreak.obj = o;
- lBreak.pos = pos;
- lBreak.nextBreakablePosition = nextBreakable;
+ lBreak.moveTo(o, pos, nextBreakable);
skipTrailingWhitespace(lBreak, isLineEmpty, previousLineBrokeCleanly);
}
}
@@ -1934,7 +2006,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
if (hyphenated)
goto end;
}
- if (lBreak.obj && shouldPreserveNewline(lBreak.obj) && lBreak.obj->isText() && toRenderText(lBreak.obj)->textLength() && !toRenderText(lBreak.obj)->isWordBreak() && toRenderText(lBreak.obj)->characters()[lBreak.pos] == '\n') {
+ if (lBreak.m_obj && shouldPreserveNewline(lBreak.m_obj) && lBreak.m_obj->isText() && toRenderText(lBreak.m_obj)->textLength() && !toRenderText(lBreak.m_obj)->isWordBreak() && toRenderText(lBreak.m_obj)->characters()[lBreak.m_pos] == '\n') {
if (!stoppedIgnoringSpaces && pos > 0) {
// We need to stop right before the newline and then start up again.
addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop
@@ -1943,7 +2015,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
lBreak.increment();
previousLineBrokeCleanly = true;
}
- if (lBreak.obj && lBreak.pos && lBreak.obj->isText() && toRenderText(lBreak.obj)->textLength() && toRenderText(lBreak.obj)->characters()[lBreak.pos - 1] == softHyphen && style->hyphens() != HyphensNone)
+ if (lBreak.m_obj && lBreak.m_pos && lBreak.m_obj->isText() && toRenderText(lBreak.m_obj)->textLength() && toRenderText(lBreak.m_obj)->characters()[lBreak.m_pos - 1] == softHyphen && style->hyphens() != HyphensNone)
hyphenated = true;
goto end; // Didn't fit. Jump to the end.
} else {
@@ -1963,9 +2035,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
addMidpoint(lineMidpointState, InlineIterator(0, o, pos - 1)); // Stop
addMidpoint(lineMidpointState, InlineIterator(0, o, pos)); // Start
}
- lBreak.obj = o;
- lBreak.pos = pos;
- lBreak.nextBreakablePosition = nextBreakable;
+ lBreak.moveTo(o, pos, nextBreakable);
lBreak.increment();
previousLineBrokeCleanly = true;
return lBreak;
@@ -1975,9 +2045,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
w += tmpW;
wrapW = 0;
tmpW = 0;
- lBreak.obj = o;
- lBreak.pos = pos;
- lBreak.nextBreakablePosition = nextBreakable;
+ lBreak.moveTo(o, pos, nextBreakable);
// Auto-wrapping text should not wrap in the middle of a word once it has had an
// opportunity to break after a word.
breakWords = false;
@@ -1986,9 +2054,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
if (midWordBreak) {
// Remember this as a breakable position in case
// adding the end width forces a break.
- lBreak.obj = o;
- lBreak.pos = pos;
- lBreak.nextBreakablePosition = nextBreakable;
+ lBreak.moveTo(o, pos, nextBreakable);
midWordBreak &= (breakWords || breakAll);
}
@@ -2020,22 +2086,21 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
}
if (currentCharacterIsSpace && !previousCharacterIsSpace) {
- ignoreStart.obj = o;
- ignoreStart.pos = pos;
+ ignoreStart.m_obj = o;
+ ignoreStart.m_pos = pos;
}
if (!currentCharacterIsWS && previousCharacterIsWS) {
- if (autoWrap && o->style()->breakOnlyAfterWhiteSpace()) {
- lBreak.obj = o;
- lBreak.pos = pos;
- lBreak.nextBreakablePosition = nextBreakable;
- }
+ if (autoWrap && o->style()->breakOnlyAfterWhiteSpace())
+ lBreak.moveTo(o, pos, nextBreakable);
}
if (collapseWhiteSpace && currentCharacterIsSpace && !ignoringSpaces)
trailingSpaceObject = o;
- else if (!o->style()->collapseWhiteSpace() || !currentCharacterIsSpace)
+ else if (!o->style()->collapseWhiteSpace() || !currentCharacterIsSpace) {
trailingSpaceObject = 0;
+ trailingPositionedBoxes.clear();
+ }
pos++;
len--;
@@ -2047,8 +2112,13 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
tmpW += additionalTmpW;
tmpW += inlineLogicalWidth(o, !appliedStartWidth, true);
- if (canHyphenate && w + tmpW > width) {
- tryHyphenating(t, f, style->locale(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, pos, w + tmpW - additionalTmpW, width, isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated);
+ if (w + tmpW > width) {
+ if (canHyphenate)
+ tryHyphenating(t, f, style->locale(), style->hyphenationLimitBefore(), style->hyphenationLimitAfter(), lastSpace, pos, w + tmpW - additionalTmpW, width, isFixedPitch, collapseWhiteSpace, lastSpaceWordSpacing, lBreak, nextBreakable, hyphenated);
+
+ if (!hyphenated && lBreak.m_obj && lBreak.m_pos && lBreak.m_obj->isText() && toRenderText(lBreak.m_obj)->textLength() && toRenderText(lBreak.m_obj)->characters()[lBreak.m_pos - 1] == softHyphen && style->hyphens() != HyphensNone)
+ hyphenated = true;
+
if (hyphenated)
goto end;
}
@@ -2057,7 +2127,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
RenderObject* next = bidiNext(this, o);
bool checkForBreak = autoWrap;
- if (w && w + tmpW > width && lBreak.obj && currWS == NOWRAP)
+ if (w && w + tmpW > width && lBreak.m_obj && currWS == NOWRAP)
checkForBreak = true;
else if (next && o->isText() && next->isText() && !next->isBR()) {
if (autoWrap || (next->style()->autoWrap())) {
@@ -2084,9 +2154,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
if (canPlaceOnLine && checkForBreak) {
w += tmpW;
tmpW = 0;
- lBreak.obj = next;
- lBreak.pos = 0;
- lBreak.nextBreakablePosition = -1;
+ lBreak.moveToStartOf(next);
}
}
}
@@ -2094,8 +2162,10 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
if (checkForBreak && (w + tmpW > width)) {
// if we have floats, try to get below them.
- if (currentCharacterIsSpace && !ignoringSpaces && o->style()->collapseWhiteSpace())
+ if (currentCharacterIsSpace && !ignoringSpaces && o->style()->collapseWhiteSpace()) {
trailingSpaceObject = 0;
+ trailingPositionedBoxes.clear();
+ }
if (w)
goto end;
@@ -2114,9 +2184,7 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
if (last->isReplaced() && autoWrap && (!last->isImage() || allowImagesToBreak) && (!last->isListMarker() || toRenderListMarker(last)->isInside())) {
w += tmpW;
tmpW = 0;
- lBreak.obj = next;
- lBreak.pos = 0;
- lBreak.nextBreakablePosition = -1;
+ lBreak.moveToStartOf(next);
}
}
@@ -2133,32 +2201,26 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
}
- if (w + tmpW <= width || lastWS == NOWRAP) {
- lBreak.obj = 0;
- lBreak.pos = 0;
- lBreak.nextBreakablePosition = -1;
- }
+ if (w + tmpW <= width || lastWS == NOWRAP)
+ lBreak.clear();
end:
- if (lBreak == resolver.position() && (!lBreak.obj || !lBreak.obj->isBR())) {
+ if (lBreak == resolver.position() && (!lBreak.m_obj || !lBreak.m_obj->isBR())) {
// we just add as much as possible
if (style()->whiteSpace() == PRE) {
// FIXME: Don't really understand this case.
if (pos != 0) {
- lBreak.obj = o;
- lBreak.pos = pos - 1;
- } else {
- lBreak.obj = last;
- lBreak.pos = last->isText() ? last->length() : 0;
- lBreak.nextBreakablePosition = -1;
- }
- } else if (lBreak.obj) {
+ // FIXME: This should call moveTo which would clear m_nextBreakablePosition
+ // this code as-is is likely wrong.
+ lBreak.m_obj = o;
+ lBreak.m_pos = pos - 1;
+ } else
+ lBreak.moveTo(last, last->isText() ? last->length() : 0);
+ } else if (lBreak.m_obj) {
// Don't ever break in the middle of a word if we can help it.
// There's no room at all. We just have to be on this line,
// even though we'll spill out.
- lBreak.obj = o;
- lBreak.pos = pos;
- lBreak.nextBreakablePosition = -1;
+ lBreak.moveTo(o, pos);
}
}
@@ -2174,18 +2236,40 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
// to be the actual endpoint. In both cases we just decrease our pos by 1 level to
// exclude the space, allowing it to - in effect - collapse into the newline.
if (lineMidpointState.numMidpoints % 2) {
- InlineIterator* midpoints = lineMidpointState.midpoints.data();
- midpoints[lineMidpointState.numMidpoints - 1].pos--;
- }
- //else if (lBreak.pos > 0)
- // lBreak.pos--;
- else if (lBreak.obj == 0 && trailingSpaceObject->isText()) {
+ // Find the trailing space object's midpoint.
+ int trailingSpaceMidpoint = lineMidpointState.numMidpoints - 1;
+ for ( ; trailingSpaceMidpoint >= 0 && lineMidpointState.midpoints[trailingSpaceMidpoint].m_obj != trailingSpaceObject; --trailingSpaceMidpoint) { }
+ ASSERT(trailingSpaceMidpoint >= 0);
+ lineMidpointState.midpoints[trailingSpaceMidpoint].m_pos--;
+
+ // Now make sure every single trailingPositionedBox following the trailingSpaceMidpoint properly stops and starts
+ // ignoring spaces.
+ size_t currentMidpoint = trailingSpaceMidpoint + 1;
+ for (size_t i = 0; i < trailingPositionedBoxes.size(); ++i) {
+ if (currentMidpoint >= lineMidpointState.numMidpoints) {
+ // We don't have a midpoint for this box yet.
+ InlineIterator ignoreStart(this, trailingPositionedBoxes[i], 0);
+ addMidpoint(lineMidpointState, ignoreStart); // Stop ignoring.
+ addMidpoint(lineMidpointState, ignoreStart); // Start ignoring again.
+ } else {
+ ASSERT(lineMidpointState.midpoints[currentMidpoint].m_obj == trailingPositionedBoxes[i]);
+ ASSERT(lineMidpointState.midpoints[currentMidpoint + 1].m_obj == trailingPositionedBoxes[i]);
+ }
+ currentMidpoint += 2;
+ }
+ } else if (!lBreak.m_obj && trailingSpaceObject->isText()) {
// Add a new end midpoint that stops right at the very end.
RenderText* text = toRenderText(trailingSpaceObject);
unsigned length = text->textLength();
unsigned pos = length >= 2 ? length - 2 : UINT_MAX;
InlineIterator endMid(0, trailingSpaceObject, pos);
addMidpoint(lineMidpointState, endMid);
+ for (size_t i = 0; i < trailingPositionedBoxes.size(); ++i) {
+ ignoreStart.m_obj = trailingPositionedBoxes[i];
+ ignoreStart.m_pos = 0;
+ addMidpoint(lineMidpointState, ignoreStart); // Stop ignoring spaces.
+ addMidpoint(lineMidpointState, ignoreStart); // Start ignoring again.
+ }
}
}
@@ -2193,8 +2277,8 @@ InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool
// of the object. Do this adjustment to make it point to the start
// of the next object instead to avoid confusing the rest of the
// code.
- if (lBreak.pos > 0) {
- lBreak.pos--;
+ if (lBreak.m_pos > 0) {
+ lBreak.m_pos--;
lBreak.increment();
}
@@ -2205,7 +2289,7 @@ void RenderBlock::addOverflowFromInlineChildren()
{
int endPadding = hasOverflowClip() ? paddingEnd() : 0;
// FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to.
- if (hasOverflowClip() && !endPadding && node() && node()->isContentEditable() && node() == node()->rootEditableElement() && style()->isLeftToRightDirection())
+ if (hasOverflowClip() && !endPadding && node() && node()->rendererIsEditable() && node() == node()->rootEditableElement() && style()->isLeftToRightDirection())
endPadding = 1;
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
addLayoutOverflow(curr->paddedLayoutOverflowRect(endPadding));
@@ -2217,7 +2301,7 @@ void RenderBlock::addOverflowFromInlineChildren()
int RenderBlock::beforeSideVisualOverflowForLine(RootInlineBox* line) const
{
// Overflow is in the block's coordinate space, which means it isn't purely physical.
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
return line->minYVisualOverflow();
return line->minXVisualOverflow();
}
@@ -2225,7 +2309,7 @@ int RenderBlock::beforeSideVisualOverflowForLine(RootInlineBox* line) const
int RenderBlock::afterSideVisualOverflowForLine(RootInlineBox* line) const
{
// Overflow is in the block's coordinate space, which means it isn't purely physical.
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
return line->maxYVisualOverflow();
return line->maxXVisualOverflow();
}
@@ -2233,7 +2317,7 @@ int RenderBlock::afterSideVisualOverflowForLine(RootInlineBox* line) const
int RenderBlock::beforeSideLayoutOverflowForLine(RootInlineBox* line) const
{
// Overflow is in the block's coordinate space, which means it isn't purely physical.
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
return line->minYLayoutOverflow();
return line->minXLayoutOverflow();
}
@@ -2241,7 +2325,7 @@ int RenderBlock::beforeSideLayoutOverflowForLine(RootInlineBox* line) const
int RenderBlock::afterSideLayoutOverflowForLine(RootInlineBox* line) const
{
// Overflow is in the block's coordinate space, which means it isn't purely physical.
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
return line->maxYLayoutOverflow();
return line->maxXLayoutOverflow();
}
diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp
index 6e7c0f2..7b32f07 100644
--- a/Source/WebCore/rendering/RenderBox.cpp
+++ b/Source/WebCore/rendering/RenderBox.cpp
@@ -130,21 +130,21 @@ int RenderBox::marginAfter() const
int RenderBox::marginStart() const
{
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
return style()->isLeftToRightDirection() ? m_marginLeft : m_marginRight;
return style()->isLeftToRightDirection() ? m_marginTop : m_marginBottom;
}
int RenderBox::marginEnd() const
{
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
return style()->isLeftToRightDirection() ? m_marginRight : m_marginLeft;
return style()->isLeftToRightDirection() ? m_marginBottom : m_marginTop;
}
void RenderBox::setMarginStart(int margin)
{
- if (style()->isHorizontalWritingMode()) {
+ if (isHorizontalWritingMode()) {
if (style()->isLeftToRightDirection())
m_marginLeft = margin;
else
@@ -159,7 +159,7 @@ void RenderBox::setMarginStart(int margin)
void RenderBox::setMarginEnd(int margin)
{
- if (style()->isHorizontalWritingMode()) {
+ if (isHorizontalWritingMode()) {
if (style()->isLeftToRightDirection())
m_marginRight = margin;
else
@@ -216,7 +216,7 @@ void RenderBox::destroy()
if (hasOverrideSize())
gOverrideSizeMap->remove(this);
- if (style() && (style()->height().isPercent() || style()->minHeight().isPercent() || style()->maxHeight().isPercent()))
+ if (style() && (style()->logicalHeight().isPercent() || style()->logicalMinHeight().isPercent() || style()->logicalMaxHeight().isPercent()))
RenderBlock::removePercentHeightDescendant(this);
RenderBoxModelObject::destroy();
@@ -299,8 +299,17 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle
{
RenderBoxModelObject::styleDidChange(diff, oldStyle);
- if (needsLayout() && oldStyle && (oldStyle->height().isPercent() || oldStyle->minHeight().isPercent() || oldStyle->maxHeight().isPercent()))
- RenderBlock::removePercentHeightDescendant(this);
+ if (needsLayout() && oldStyle) {
+ if (oldStyle && (oldStyle->logicalHeight().isPercent() || oldStyle->logicalMinHeight().isPercent() || oldStyle->logicalMaxHeight().isPercent()))
+ RenderBlock::removePercentHeightDescendant(this);
+
+ // Normally we can do optimized positioning layout for absolute/fixed positioned objects. There is one special case, however, which is
+ // when the positioned object's margin-before is changed. In this case the parent has to get a layout in order to run margin collapsing
+ // to determine the new static position.
+ if (isPositioned() && style()->hasStaticBlockPosition(isHorizontalWritingMode()) && oldStyle->marginBefore() != style()->marginBefore()
+ && parent() && !parent()->normalChildNeedsLayout())
+ parent()->setChildNeedsLayout(true);
+ }
// If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
// new zoomed coordinate space.
@@ -335,8 +344,11 @@ void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle
if (viewStyle->writingMode() != style()->writingMode() && (isRootRenderer || !document()->writingModeSetOnDocumentElement())) {
viewStyle->setWritingMode(style()->writingMode());
- if (isBodyRenderer)
+ viewRenderer->setHorizontalWritingMode(style()->isHorizontalWritingMode());
+ if (isBodyRenderer) {
document()->documentElement()->renderer()->style()->setWritingMode(style()->writingMode());
+ document()->documentElement()->renderer()->setHorizontalWritingMode(style()->isHorizontalWritingMode());
+ }
setNeedsLayoutAndPrefWidthsRecalc();
}
}
@@ -621,9 +633,9 @@ bool RenderBox::logicalScroll(ScrollLogicalDirection direction, ScrollGranularit
#if PLATFORM(MAC)
// On Mac only we reset the inline direction position when doing a document scroll (e.g., hitting Home/End).
if (granularity == ScrollByDocument)
- scrolled = l->scroll(logicalToPhysical(ScrollInlineDirectionBackward, style()->isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), ScrollByDocument, multiplier);
+ scrolled = l->scroll(logicalToPhysical(ScrollInlineDirectionBackward, isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), ScrollByDocument, multiplier);
#endif
- if (l->scroll(logicalToPhysical(direction, style()->isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
+ if (l->scroll(logicalToPhysical(direction, isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
scrolled = true;
if (scrolled) {
@@ -649,7 +661,7 @@ bool RenderBox::canBeScrolledAndHasScrollableArea() const
bool RenderBox::canBeProgramaticallyScrolled(bool) const
{
- return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->isContentEditable()))) || (node() && node()->isDocumentNode());
+ return (hasOverflowClip() && (scrollsOverflow() || (node() && node()->rendererIsEditable()))) || (node() && node()->isDocumentNode());
}
void RenderBox::autoscroll()
@@ -782,7 +794,7 @@ void RenderBox::paint(PaintInfo& paintInfo, int tx, int ty)
child->paint(childInfo, tx, ty);
}
-void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
+void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo)
{
const FillLayer* bgLayer = style()->backgroundLayers();
Color bgColor = style()->visitedDependentColor(CSSPropertyBackgroundColor);
@@ -803,21 +815,12 @@ void RenderBox::paintRootBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
// The background of the box generated by the root element covers the entire canvas, so just use
// the RenderView's docTop/Left/Width/Height accessors.
paintFillLayers(paintInfo, bgColor, bgLayer, view()->docLeft(), view()->docTop(), view()->docWidth(), view()->docHeight(), CompositeSourceOver, bodyObject);
-
- if (style()->hasBorder() && style()->display() != INLINE)
- paintBorder(paintInfo.context, tx, ty, width(), height(), style());
}
void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
{
if (!paintInfo.shouldPaintWithinRoot(this))
return;
-
- if (isRoot()) {
- paintRootBoxDecorations(paintInfo, tx, ty);
- return;
- }
-
return paintBoxDecorationsWithSize(paintInfo, tx, ty, width(), height());
}
@@ -835,11 +838,13 @@ void RenderBox::paintBoxDecorationsWithSize(PaintInfo& paintInfo, int tx, int ty
// The theme will tell us whether or not we should also paint the CSS background.
bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, IntRect(tx, ty, width, height));
if (!themePainted) {
- // The <body> only paints its background if the root element has defined a background
- // independent of the body. Go through the DOM to get to the root element's render object,
- // since the root could be inline and wrapped in an anonymous block.
- if (!isBody() || document()->documentElement()->renderer()->hasBackground())
+ if (isRoot())
+ paintRootBoxFillLayers(paintInfo);
+ else if (!isBody() || document()->documentElement()->renderer()->hasBackground()) {
+ // The <body> only paints its background if the root element has defined a background
+ // independent of the body.
paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), tx, ty, width, height);
+ }
if (style()->hasAppearance())
theme()->paintDecorations(this, paintInfo, IntRect(tx, ty, width, height));
}
@@ -1108,7 +1113,7 @@ void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase,
paintInfo.phase = originalPhase;
}
-IntRect RenderBox::overflowClipRect(int tx, int ty)
+IntRect RenderBox::overflowClipRect(int tx, int ty, OverlayScrollbarSizeRelevancy relevancy)
{
// FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
// here.
@@ -1123,8 +1128,8 @@ IntRect RenderBox::overflowClipRect(int tx, int ty)
// Subtract out scrollbars if we have them.
if (layer()) {
- clipWidth -= layer()->verticalScrollbarWidth();
- clipHeight -= layer()->horizontalScrollbarHeight();
+ clipWidth -= layer()->verticalScrollbarWidth(relevancy);
+ clipHeight -= layer()->horizontalScrollbarHeight(relevancy);
}
return IntRect(clipX, clipY, clipWidth, clipHeight);
@@ -1319,19 +1324,21 @@ void RenderBox::positionLineBox(InlineBox* box)
if (isPositioned()) {
// Cache the x position only if we were an INLINE type originally.
bool wasInline = style()->isOriginalDisplayInlineType();
- if (wasInline && style()->hasStaticInlinePosition(box->isHorizontal())) {
+ if (wasInline) {
// The value is cached in the xPos of the box. We only need this value if
// our object was inline originally, since otherwise it would have ended up underneath
// the inlines.
layer()->setStaticInlinePosition(lroundf(box->logicalLeft()));
- setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
- } else if (!wasInline && style()->hasStaticBlockPosition(box->isHorizontal())) {
+ if (style()->hasStaticInlinePosition(box->isHorizontal()))
+ setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
+ } else {
// Our object was a block originally, so we make our normal flow position be
// just below the line box (as though all the inlines that came before us got
// wrapped in an anonymous block, which is what would have happened had we been
// in flow). This value was cached in the y() of the box.
layer()->setStaticBlockPosition(box->logicalTop());
- setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
+ if (style()->hasStaticBlockPosition(box->isHorizontal()))
+ setChildNeedsLayout(true, false); // Just go ahead and mark the positioned object as needing layout, so it will update its position properly.
}
// Nuke the box.
@@ -1569,7 +1576,7 @@ void RenderBox::computeLogicalWidth()
RenderBlock* cb = containingBlock();
int containerLogicalWidth = max(0, containingBlockLogicalWidthForContent());
- bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode();
+ bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
int containerWidthInInlineDirection = containerLogicalWidth;
if (hasPerpendicularContainingBlock)
containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
@@ -1776,7 +1783,7 @@ void RenderBox::computeLogicalHeight()
computePositionedLogicalHeight();
} else {
RenderBlock* cb = containingBlock();
- bool hasPerpendicularContainingBlock = cb->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode();
+ bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode();
if (!hasPerpendicularContainingBlock)
computeBlockDirectionMargins(cb);
@@ -1863,7 +1870,7 @@ void RenderBox::computeLogicalHeight()
if (document()->printing())
visHeight = static_cast<int>(view()->pageLogicalHeight());
else {
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
visHeight = view()->viewHeight();
else
visHeight = view()->viewWidth();
@@ -1896,18 +1903,20 @@ int RenderBox::computeLogicalHeightUsing(const Length& h)
int RenderBox::computePercentageLogicalHeight(const Length& height)
{
int result = -1;
+
+ // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
+ // block that may have a specified height and then use it. In strict mode, this violates the
+ // specification, which states that percentage heights just revert to auto if the containing
+ // block has an auto height. We still skip anonymous containing blocks in both modes, though, and look
+ // only at explicit containers.
bool skippedAutoHeightContainingBlock = false;
RenderBlock* cb = containingBlock();
- if (document()->inQuirksMode()) {
- // In quirks mode, blocks with auto height are skipped, and we keep looking for an enclosing
- // block that may have a specified height and then use it. In strict mode, this violates the
- // specification, which states that percentage heights just revert to auto if the containing
- // block has an auto height.
- while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() && cb->style()->logicalHeight().isAuto()) {
- skippedAutoHeightContainingBlock = true;
- cb = cb->containingBlock();
- cb->addPercentHeightDescendant(this);
- }
+ while (!cb->isRenderView() && !cb->isBody() && !cb->isTableCell() && !cb->isPositioned() && cb->style()->logicalHeight().isAuto()) {
+ if (!document()->inQuirksMode() && !cb->isAnonymousBlock())
+ break;
+ skippedAutoHeightContainingBlock = true;
+ cb = cb->containingBlock();
+ cb->addPercentHeightDescendant(this);
}
// A positioned element that specified both top/bottom or that specifies height should be treated as though it has a height
@@ -2071,7 +2080,7 @@ int RenderBox::availableLogicalHeightUsing(const Length& h) const
return computeContentBoxLogicalHeight(h.value());
if (isRenderView())
- return style()->isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth();
+ return 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
@@ -2126,7 +2135,7 @@ int RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObje
}
#endif
- if (checkForPerpendicularWritingMode && containingBlock->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode())
+ if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
return containingBlockLogicalHeightForPositioned(containingBlock, false);
if (containingBlock->isBox())
@@ -2166,7 +2175,7 @@ int RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObj
}
#endif
- if (checkForPerpendicularWritingMode && containingBlock->style()->isHorizontalWritingMode() != style()->isHorizontalWritingMode())
+ if (checkForPerpendicularWritingMode && containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
return containingBlockLogicalWidthForPositioned(containingBlock, false);
if (containingBlock->isBox())
@@ -2184,7 +2193,7 @@ int RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObj
int heightResult;
IntRect boundingBox = flow->linesBoundingBox();
- if (containingBlock->style()->isHorizontalWritingMode())
+ if (containingBlock->isHorizontalWritingMode())
heightResult = boundingBox.height();
else
heightResult = boundingBox.width();
@@ -2201,7 +2210,7 @@ static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh
// FIXME: The static distance computation has not been patched for mixed writing modes yet.
if (containerDirection == LTR) {
int staticPosition = child->layer()->staticInlinePosition() - containerBlock->borderLogicalLeft();
- for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->parent()) {
+ for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
if (curr->isBox())
staticPosition += toRenderBox(curr)->logicalLeft();
}
@@ -2210,7 +2219,7 @@ static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh
RenderBox* enclosingBox = child->parent()->enclosingBox();
int staticPosition = child->layer()->staticInlinePosition() + containerLogicalWidth + containerBlock->borderLogicalRight();
staticPosition -= enclosingBox->logicalWidth();
- for (RenderObject* curr = enclosingBox; curr && curr != containerBlock; curr = curr->parent()) {
+ for (RenderObject* curr = enclosingBox; curr && curr != containerBlock; curr = curr->container()) {
if (curr->isBox())
staticPosition -= toRenderBox(curr)->logicalLeft();
}
@@ -2260,7 +2269,7 @@ void RenderBox::computePositionedLogicalWidth()
// instead of the the container block's.
TextDirection containerDirection = (document()->inQuirksMode()) ? parent()->style()->direction() : containerBlock->style()->direction();
- bool isHorizontal = style()->isHorizontalWritingMode();
+ bool isHorizontal = isHorizontalWritingMode();
const int bordersPlusPadding = borderAndPaddingLogicalWidth();
const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
const Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom();
@@ -2365,11 +2374,11 @@ static void computeLogicalLeftPositionedOffset(int& logicalLeftPos, const Render
{
// Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
// along this axis, then we need to flip the coordinate. This can only happen if the containing block is both a flipped mode and perpendicular to us.
- if (containerBlock->style()->isHorizontalWritingMode() != child->style()->isHorizontalWritingMode() && containerBlock->style()->isFlippedBlocksWritingMode()) {
+ if (containerBlock->isHorizontalWritingMode() != child->isHorizontalWritingMode() && containerBlock->style()->isFlippedBlocksWritingMode()) {
logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeftPos;
- logicalLeftPos += (child->style()->isHorizontalWritingMode() ? containerBlock->borderRight() : containerBlock->borderBottom());
+ logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderRight() : containerBlock->borderBottom());
} else
- logicalLeftPos += (child->style()->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop());
+ logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock->borderLeft() : containerBlock->borderTop());
}
void RenderBox::computePositionedLogicalWidthUsing(Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection,
@@ -2552,7 +2561,7 @@ static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom
// FIXME: The static distance computation has not been patched for mixed writing modes.
int staticLogicalTop = child->layer()->staticBlockPosition() - containerBlock->borderBefore();
- for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->parent()) {
+ for (RenderObject* curr = child->parent(); curr && curr != containerBlock; curr = curr->container()) {
if (curr->isBox() && !curr->isTableRow())
staticLogicalTop += toRenderBox(curr)->logicalTop();
}
@@ -2578,7 +2587,7 @@ void RenderBox::computePositionedLogicalHeight()
const int containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
- bool isHorizontal = style()->isHorizontalWritingMode();
+ bool isHorizontal = isHorizontalWritingMode();
bool isFlipped = style()->isFlippedBlocksWritingMode();
const int bordersPlusPadding = borderAndPaddingLogicalHeight();
const Length marginBefore = style()->marginBefore();
@@ -2668,18 +2677,18 @@ static void computeLogicalTopPositionedOffset(int& logicalTopPos, const RenderBo
{
// Deal with differing writing modes here. Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
// along this axis, then we need to flip the coordinate. This can only happen if the containing block is both a flipped mode and perpendicular to us.
- if ((child->style()->isFlippedBlocksWritingMode() && child->style()->isHorizontalWritingMode() != containerBlock->style()->isHorizontalWritingMode())
- || (child->style()->isFlippedBlocksWritingMode() != containerBlock->style()->isFlippedBlocksWritingMode() && child->style()->isHorizontalWritingMode() == containerBlock->style()->isHorizontalWritingMode()))
+ if ((child->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode())
+ || (child->style()->isFlippedBlocksWritingMode() != containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()))
logicalTopPos = containerLogicalHeight - logicalHeightValue - logicalTopPos;
// Our offset is from the logical bottom edge in a flipped environment, e.g., right for vertical-rl and bottom for horizontal-bt.
- if (containerBlock->style()->isFlippedBlocksWritingMode() && child->style()->isHorizontalWritingMode() == containerBlock->style()->isHorizontalWritingMode()) {
- if (child->style()->isHorizontalWritingMode())
+ if (containerBlock->style()->isFlippedBlocksWritingMode() && child->isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) {
+ if (child->isHorizontalWritingMode())
logicalTopPos += containerBlock->borderBottom();
else
logicalTopPos += containerBlock->borderRight();
} else {
- if (child->style()->isHorizontalWritingMode())
+ if (child->isHorizontalWritingMode())
logicalTopPos += containerBlock->borderTop();
else
logicalTopPos += containerBlock->borderLeft();
@@ -2825,7 +2834,7 @@ void RenderBox::computePositionedLogicalWidthReplaced()
TextDirection containerDirection = (document()->inQuirksMode()) ? parent()->style()->direction() : containerBlock->style()->direction();
// Variables to solve.
- bool isHorizontal = style()->isHorizontalWritingMode();
+ bool isHorizontal = isHorizontalWritingMode();
Length logicalLeft = style()->logicalLeft();
Length logicalRight = style()->logicalRight();
Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop();
@@ -2985,7 +2994,7 @@ void RenderBox::computePositionedLogicalHeightReplaced()
const int containerLogicalHeight = containingBlockLogicalHeightForPositioned(containerBlock);
// Variables to solve.
- bool isHorizontal = style()->isHorizontalWritingMode();
+ bool isHorizontal = isHorizontalWritingMode();
bool isFlipped = style()->isFlippedBlocksWritingMode();
Length marginBefore = style()->marginBefore();
Length marginAfter = style()->marginAfter();
@@ -3146,7 +3155,7 @@ VisiblePosition RenderBox::positionForPoint(const IntPoint& point)
{
// no children...return this render object's element, if there is one, and offset 0
if (!firstChild())
- return createVisiblePosition(node() ? firstDeepEditingPositionForNode(node()) : Position(0, 0));
+ return createVisiblePosition(node() ? firstPositionInOrBeforeNode(node()) : Position(0, 0));
int xPos = point.x();
int yPos = point.y();
@@ -3157,8 +3166,8 @@ VisiblePosition RenderBox::positionForPoint(const IntPoint& point)
if (xPos < 0 || xPos > right || yPos < 0 || yPos > bottom) {
if (xPos <= right / 2)
- return createVisiblePosition(firstDeepEditingPositionForNode(node()));
- return createVisiblePosition(lastDeepEditingPositionForNode(node()));
+ return createVisiblePosition(firstPositionInOrBeforeNode(node()));
+ return createVisiblePosition(lastPositionInOrAfterNode(node()));
}
}
@@ -3229,7 +3238,7 @@ VisiblePosition RenderBox::positionForPoint(const IntPoint& point)
if (closestRenderer)
return closestRenderer->positionForCoordinates(newX - closestRenderer->x(), newY - closestRenderer->y());
- return createVisiblePosition(firstDeepEditingPositionForNode(node()));
+ return createVisiblePosition(firstPositionInOrBeforeNode(node()));
}
bool RenderBox::shrinkToAvoidFloats() const
@@ -3293,8 +3302,8 @@ void RenderBox::addLayoutOverflow(const IntRect& rect)
// Overflow is in the block's coordinate space and thus is flipped for horizontal-bt and vertical-rl
// writing modes. At this stage that is actually a simplification, since we can treat horizontal-tb/bt as the same
// and vertical-lr/rl as the same.
- bool hasTopOverflow = !style()->isLeftToRightDirection() && !style()->isHorizontalWritingMode();
- bool hasLeftOverflow = !style()->isLeftToRightDirection() && style()->isHorizontalWritingMode();
+ bool hasTopOverflow = !style()->isLeftToRightDirection() && !isHorizontalWritingMode();
+ bool hasLeftOverflow = !style()->isLeftToRightDirection() && isHorizontalWritingMode();
if (!hasTopOverflow)
overflowRect.shiftYEdgeTo(max(overflowRect.y(), clientBox.y()));
@@ -3414,13 +3423,14 @@ IntRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle) co
if (!hasOverflowClip())
rect.unite(layoutOverflowRect());
- if (isRelPositioned() || hasTransform()) {
+ bool hasTransform = hasLayer() && layer()->transform();
+ if (isRelPositioned() || hasTransform) {
// If we are relatively positioned or if we have a transform, then we have to convert
// this rectangle into physical coordinates, apply relative positioning and transforms
// to it, and then convert it back.
flipForWritingMode(rect);
- if (hasTransform())
+ if (hasTransform)
rect = layer()->currentTransform().mapRect(rect);
if (isRelPositioned())
@@ -3452,7 +3462,7 @@ IntPoint RenderBox::flipForWritingMode(const RenderBox* child, const IntPoint& p
// The child is going to add in its x() and y(), so we have to make sure it ends up in
// the right place.
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
return IntPoint(point.x(), point.y() + height() - child->height() - child->y() - (adjustment == ParentToChildFlippingAdjustment ? child->y() : 0));
return IntPoint(point.x() + width() - child->width() - child->x() - (adjustment == ParentToChildFlippingAdjustment ? child->x() : 0), point.y());
}
@@ -3462,7 +3472,7 @@ void RenderBox::flipForWritingMode(IntRect& rect) const
if (!style()->isFlippedBlocksWritingMode())
return;
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
rect.setY(height() - rect.maxY());
else
rect.setX(width() - rect.maxX());
@@ -3479,7 +3489,7 @@ IntPoint RenderBox::flipForWritingMode(const IntPoint& position) const
{
if (!style()->isFlippedBlocksWritingMode())
return position;
- return style()->isHorizontalWritingMode() ? IntPoint(position.x(), height() - position.y()) : IntPoint(width() - position.x(), position.y());
+ return isHorizontalWritingMode() ? IntPoint(position.x(), height() - position.y()) : IntPoint(width() - position.x(), position.y());
}
IntPoint RenderBox::flipForWritingModeIncludingColumns(const IntPoint& point) const
@@ -3493,14 +3503,14 @@ IntSize RenderBox::flipForWritingMode(const IntSize& offset) const
{
if (!style()->isFlippedBlocksWritingMode())
return offset;
- return style()->isHorizontalWritingMode() ? IntSize(offset.width(), height() - offset.height()) : IntSize(width() - offset.width(), offset.height());
+ return isHorizontalWritingMode() ? IntSize(offset.width(), height() - offset.height()) : IntSize(width() - offset.width(), offset.height());
}
FloatPoint RenderBox::flipForWritingMode(const FloatPoint& position) const
{
if (!style()->isFlippedBlocksWritingMode())
return position;
- return style()->isHorizontalWritingMode() ? FloatPoint(position.x(), height() - position.y()) : FloatPoint(width() - position.x(), position.y());
+ return isHorizontalWritingMode() ? FloatPoint(position.x(), height() - position.y()) : FloatPoint(width() - position.x(), position.y());
}
void RenderBox::flipForWritingMode(FloatRect& rect) const
@@ -3508,7 +3518,7 @@ void RenderBox::flipForWritingMode(FloatRect& rect) const
if (!style()->isFlippedBlocksWritingMode())
return;
- if (style()->isHorizontalWritingMode())
+ if (isHorizontalWritingMode())
rect.setY(height() - rect.maxY());
else
rect.setX(width() - rect.maxX());
diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h
index f0bd30d..ccedc66 100644
--- a/Source/WebCore/rendering/RenderBox.h
+++ b/Source/WebCore/rendering/RenderBox.h
@@ -33,6 +33,8 @@ struct PaintInfo;
enum LogicalWidthType { LogicalWidth, MinLogicalWidth, MaxLogicalWidth };
+enum OverlayScrollbarSizeRelevancy { IgnoreOverlayScrollbarSize, IncludeOverlayScrollbarSize };
+
class RenderBox : public RenderBoxModelObject {
public:
RenderBox(Node*);
@@ -334,7 +336,7 @@ public:
virtual IntRect localCaretRect(InlineBox*, int caretOffset, int* extraWidthToEndOfLine = 0);
- virtual IntRect overflowClipRect(int tx, int ty);
+ virtual IntRect overflowClipRect(int tx, int ty, OverlayScrollbarSizeRelevancy relevancy = IgnoreOverlayScrollbarSize);
IntRect clipRect(int tx, int ty);
virtual bool hasControlClip() const { return false; }
virtual IntRect controlClipRect(int /*tx*/, int /*ty*/) const { return IntRect(); }
@@ -422,11 +424,12 @@ protected:
virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState&) const;
virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const;
+ void paintRootBoxFillLayers(const PaintInfo&);
+
private:
bool includeVerticalScrollbarSize() const;
bool includeHorizontalScrollbarSize() const;
- void paintRootBoxDecorations(PaintInfo&, int tx, int ty);
// Returns true if we did a full repaint
bool repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer* layers, bool drawingBackground);
diff --git a/Source/WebCore/rendering/RenderBoxModelObject.cpp b/Source/WebCore/rendering/RenderBoxModelObject.cpp
index eec048e..3e2974d 100644
--- a/Source/WebCore/rendering/RenderBoxModelObject.cpp
+++ b/Source/WebCore/rendering/RenderBoxModelObject.cpp
@@ -303,7 +303,7 @@ void RenderBoxModelObject::styleWillChange(StyleDifference diff, const RenderSty
repaint();
}
- if (diff == StyleDifferenceLayout) {
+ if (diff == StyleDifferenceLayout || diff == StyleDifferenceSimplifiedLayout) {
// When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could
// end up being destroyed.
if (hasLayer()) {
@@ -346,8 +346,10 @@ void RenderBoxModelObject::styleDidChange(StyleDifference diff, const RenderStyl
m_layer = new (renderArena()) RenderLayer(this);
setHasLayer(true);
m_layer->insertOnlyThisLayer();
- if (parent() && !needsLayout() && containingBlock())
+ if (parent() && !needsLayout() && containingBlock()) {
+ m_layer->setNeedsFullRepaint();
m_layer->updateLayerPositions();
+ }
}
} else if (layer() && layer()->parent()) {
setHasTransform(false); // Either a transform wasn't specified or the object doesn't support transforms, so just null out the bit.
@@ -371,6 +373,7 @@ void RenderBoxModelObject::updateBoxModelInfoFromStyle()
setHasBoxDecorations(hasBackground() || style()->hasBorder() || style()->hasAppearance() || style()->boxShadow());
setInline(style()->isDisplayInlineType());
setRelPositioned(style()->position() == RelativePosition);
+ setHorizontalWritingMode(style()->isHorizontalWritingMode());
}
int RenderBoxModelObject::relativePositionOffsetX() const
diff --git a/Source/WebCore/rendering/RenderCombineText.cpp b/Source/WebCore/rendering/RenderCombineText.cpp
index 250ec9b..37ca1ed 100644
--- a/Source/WebCore/rendering/RenderCombineText.cpp
+++ b/Source/WebCore/rendering/RenderCombineText.cpp
@@ -37,6 +37,7 @@ RenderCombineText::RenderCombineText(Node* node, PassRefPtr<StringImpl> string)
void RenderCombineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
+ setStyleInternal(RenderStyle::clone(style()));
RenderText::styleDidChange(diff, oldStyle);
if (m_isCombined)
@@ -93,12 +94,12 @@ void RenderCombineText::combineText()
return;
TextRun run = TextRun(String(text()));
- FontDescription description = style()->font().fontDescription();
+ FontDescription description = originalFont().fontDescription();
float emWidth = description.computedSize() * textCombineMargin;
bool shouldUpdateFont = false;
description.setOrientation(Horizontal); // We are going to draw combined text horizontally.
- m_combinedTextWidth = style()->font().width(run);
+ m_combinedTextWidth = originalFont().width(run);
m_isCombined = m_combinedTextWidth <= emWidth;
if (m_isCombined)
@@ -122,12 +123,14 @@ void RenderCombineText::combineText()
}
}
+ if (!m_isCombined)
+ shouldUpdateFont = style()->setFontDescription(originalFont().fontDescription());
+
if (shouldUpdateFont)
style()->font().update(style()->font().fontSelector());
if (m_isCombined) {
- static const UChar newCharacter = objectReplacementCharacter;
- DEFINE_STATIC_LOCAL(String, objectReplacementCharacterString, (&newCharacter, 1));
+ DEFINE_STATIC_LOCAL(String, objectReplacementCharacterString, (&objectReplacementCharacter, 1));
RenderText::setTextInternal(objectReplacementCharacterString.impl());
}
}
diff --git a/Source/WebCore/rendering/RenderCombineText.h b/Source/WebCore/rendering/RenderCombineText.h
index 3484ab7..406c3f6 100644
--- a/Source/WebCore/rendering/RenderCombineText.h
+++ b/Source/WebCore/rendering/RenderCombineText.h
@@ -34,8 +34,10 @@ public:
void charactersToRender(int start, const UChar*& characters, int& length) const;
bool isCombined() const { return m_isCombined; }
float combinedTextWidth(const Font& font) const { return font.size(); }
+ const Font& originalFont() const { return parent()->style()->font(); }
private:
+ virtual bool isCombineText() const { return true; }
virtual float width(unsigned from, unsigned length, const Font&, float xPosition, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
virtual const char* renderName() const { return "RenderCombineText"; }
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
@@ -48,13 +50,13 @@ private:
inline RenderCombineText* toRenderCombineText(RenderObject* object)
{
- ASSERT(!object || object->isText());
+ ASSERT(!object || object->isCombineText());
return static_cast<RenderCombineText*>(object);
}
inline const RenderCombineText* toRenderCombineText(const RenderObject* object)
{
- ASSERT(!object || object->isText());
+ ASSERT(!object || object->isCombineText());
return static_cast<const RenderCombineText*>(object);
}
diff --git a/Source/WebCore/rendering/RenderCounter.cpp b/Source/WebCore/rendering/RenderCounter.cpp
index f4a8736..9b8c493 100644
--- a/Source/WebCore/rendering/RenderCounter.cpp
+++ b/Source/WebCore/rendering/RenderCounter.cpp
@@ -316,7 +316,7 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString&
previousSibling = parent ? currentCounter : 0;
return parent;
}
- // We are not a reset node or the previous reset must be on an ancestor of our renderer
+ // We are not a reset node or the previous reset must be on an ancestor of our owner renderer
// hence we must be a child of that reset counter.
parent = currentCounter;
ASSERT(previousSibling->parent() == currentCounter);
@@ -325,7 +325,7 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString&
// CurrentCounter, the counter at the EndSearchRenderer, is not reset.
if (!isReset || !areRenderersElementsSiblings(currentRenderer, counterOwner)) {
// If the node we are placing is not reset or we have found a counter that is attached
- // to an ancestor of the placed counter's renderer we know we are a sibling of that node.
+ // to an ancestor of the placed counter's owner renderer we know we are a sibling of that node.
ASSERT(currentCounter->parent() == previousSibling->parent());
parent = currentCounter->parent();
return true;
@@ -352,9 +352,9 @@ static bool findPlaceForCounter(RenderObject* counterOwner, const AtomicString&
previousSibling = currentCounter;
}
}
- // We come here if the previous sibling or parent of our renderer had no
+ // We come here if the previous sibling or parent of our owner renderer had no
// good counter, or we are a reset node and the counter on the previous sibling
- // of our renderer was not a reset counter.
+ // of our owner renderer was not a reset counter.
// Set a new goal for the end of the search.
searchEndRenderer = previousSiblingOrParent(currentRenderer);
} else {
@@ -450,11 +450,16 @@ RenderCounter::RenderCounter(Document* node, const CounterContent& counter)
: RenderText(node, StringImpl::empty())
, m_counter(counter)
, m_counterNode(0)
+ , m_nextForSameCounter(0)
{
}
RenderCounter::~RenderCounter()
{
+ if (m_counterNode) {
+ m_counterNode->removeRenderer(this);
+ ASSERT(!m_counterNode);
+ }
}
const char* RenderCounter::renderName() const
@@ -469,12 +474,21 @@ bool RenderCounter::isCounter() const
PassRefPtr<StringImpl> RenderCounter::originalText() const
{
- if (!parent())
- return 0;
-
- if (!m_counterNode)
- m_counterNode = makeCounterNode(parent(), m_counter.identifier(), true);
-
+ if (!m_counterNode) {
+ RenderObject* beforeAfterContainer = parent();
+ while (true) {
+ if (!beforeAfterContainer)
+ return 0;
+ if (!beforeAfterContainer->isAnonymous())
+ return 0; // RenderCounters are restricted to before and after pseudo elements
+ PseudoId containerStyle = beforeAfterContainer->style()->styleType();
+ if ((containerStyle == BEFORE) || (containerStyle == AFTER))
+ break;
+ beforeAfterContainer = beforeAfterContainer->parent();
+ }
+ makeCounterNode(beforeAfterContainer, m_counter.identifier(), true)->addRenderer(const_cast<RenderCounter*>(this));
+ ASSERT(m_counterNode);
+ }
CounterNode* child = m_counterNode;
int value = child->actsAsReset() ? child->value() : child->countInParent();
@@ -499,11 +513,12 @@ void RenderCounter::computePreferredLogicalWidths(float lead)
RenderText::computePreferredLogicalWidths(lead);
}
-void RenderCounter::invalidate(const AtomicString& identifier)
+void RenderCounter::invalidate()
{
- if (m_counter.identifier() != identifier)
+ m_counterNode->removeRenderer(this);
+ ASSERT(!m_counterNode);
+ if (documentBeingDestroyed())
return;
- m_counterNode = 0;
setNeedsLayoutAndPrefWidthsRecalc();
}
@@ -512,28 +527,18 @@ static void destroyCounterNodeWithoutMapRemoval(const AtomicString& identifier,
CounterNode* previous;
for (RefPtr<CounterNode> child = node->lastDescendant(); child && child != node; child = previous) {
previous = child->previousInPreOrder();
- 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()) {
- RenderObjectChildList* children = child->renderer()->virtualChildren();
- if (children)
- children->invalidateCounters(child->renderer(), identifier);
- }
- }
- RenderObject* renderer = node->renderer();
- if (!renderer->documentBeingDestroyed()) {
- if (RenderObjectChildList* children = renderer->virtualChildren())
- children->invalidateCounters(renderer, identifier);
+ child->parent()->removeChild(child.get());
+ ASSERT(counterMaps().get(child->owner())->get(identifier.impl()) == child);
+ counterMaps().get(child->owner())->remove(identifier.impl());
}
if (CounterNode* parent = node->parent())
- parent->removeChild(node, identifier);
+ parent->removeChild(node);
}
-void RenderCounter::destroyCounterNodes(RenderObject* renderer)
+void RenderCounter::destroyCounterNodes(RenderObject* owner)
{
CounterMaps& maps = counterMaps();
- CounterMaps::iterator mapsIterator = maps.find(renderer);
+ CounterMaps::iterator mapsIterator = maps.find(owner);
if (mapsIterator == maps.end())
return;
CounterMap* map = mapsIterator->second;
@@ -544,12 +549,12 @@ void RenderCounter::destroyCounterNodes(RenderObject* renderer)
}
maps.remove(mapsIterator);
delete map;
- renderer->m_hasCounterNodeMap = false;
+ owner->m_hasCounterNodeMap = false;
}
-void RenderCounter::destroyCounterNode(RenderObject* renderer, const AtomicString& identifier)
+void RenderCounter::destroyCounterNode(RenderObject* owner, const AtomicString& identifier)
{
- CounterMap* map = counterMaps().get(renderer);
+ CounterMap* map = counterMaps().get(owner);
if (!map)
return;
CounterMap::iterator mapIterator = map->find(identifier.impl());
@@ -600,7 +605,7 @@ static void updateCounters(RenderObject* renderer)
if (newParent == parent && newPreviousSibling == node->previousSibling())
continue;
if (parent)
- parent->removeChild(node.get(), it->first.get());
+ parent->removeChild(node.get());
if (newParent)
newParent->insertAfter(node.get(), newPreviousSibling, it->first.get());
}
@@ -684,6 +689,7 @@ void showCounterRendererTree(const WebCore::RenderObject* renderer, const char*
current->nextSibling(), current->m_hasCounterNodeMap?
counterName ? WebCore::counterMaps().get(current)->get(identifier.impl()).get() : (WebCore::CounterNode*)1 : (WebCore::CounterNode*)0);
}
+ fflush(stderr);
}
#endif // NDEBUG
diff --git a/Source/WebCore/rendering/RenderCounter.h b/Source/WebCore/rendering/RenderCounter.h
index 35ffc35..9557ae3 100644
--- a/Source/WebCore/rendering/RenderCounter.h
+++ b/Source/WebCore/rendering/RenderCounter.h
@@ -34,12 +34,6 @@ public:
RenderCounter(Document*, const CounterContent&);
virtual ~RenderCounter();
- // Removes the reference to the CounterNode associated with this renderer
- // if its identifier matches the argument.
- // This is used to cause a counter display update when the CounterNode
- // tree for identifier changes.
- void invalidate(const AtomicString& identifier);
-
static void destroyCounterNodes(RenderObject*);
static void destroyCounterNode(RenderObject*, const AtomicString& identifier);
static void rendererSubtreeAttached(RenderObject*);
@@ -52,8 +46,14 @@ private:
virtual void computePreferredLogicalWidths(float leadWidth);
+ // Removes the reference to the CounterNode associated with this renderer.
+ // This is used to cause a counter display update when the CounterNode tree changes.
+ void invalidate();
+
CounterContent m_counter;
- mutable CounterNode* m_counterNode;
+ CounterNode* m_counterNode;
+ RenderCounter* m_nextForSameCounter;
+ friend class CounterNode;
};
inline RenderCounter* toRenderCounter(RenderObject* object)
diff --git a/Source/WebCore/rendering/RenderDataGrid.cpp b/Source/WebCore/rendering/RenderDataGrid.cpp
index c322389..5057a5f 100644
--- a/Source/WebCore/rendering/RenderDataGrid.cpp
+++ b/Source/WebCore/rendering/RenderDataGrid.cpp
@@ -46,10 +46,16 @@ static const int cDefaultWidth = 300;
RenderDataGrid::RenderDataGrid(Element* elt)
: RenderBlock(elt)
{
+ if (Page* page = frame()->page()) {
+ m_page = page;
+ m_page->addScrollableArea(this);
+ }
}
RenderDataGrid::~RenderDataGrid()
{
+ if (m_page)
+ m_page->removeScrollableArea(this);
}
void RenderDataGrid::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
@@ -256,6 +262,14 @@ IntPoint RenderDataGrid::convertFromContainingViewToScrollbar(const Scrollbar* s
return point;
}
+bool RenderDataGrid::shouldSuspendScrollAnimations() const
+{
+ RenderView* view = this->view();
+ if (!view)
+ return true;
+ return view->frameView()->shouldSuspendScrollAnimations();
+}
+
}
#endif
diff --git a/Source/WebCore/rendering/RenderDataGrid.h b/Source/WebCore/rendering/RenderDataGrid.h
index 852010c..4f897d1 100644
--- a/Source/WebCore/rendering/RenderDataGrid.h
+++ b/Source/WebCore/rendering/RenderDataGrid.h
@@ -77,8 +77,13 @@ private:
virtual IntRect convertFromContainingViewToScrollbar(const Scrollbar*, const IntRect&) const;
virtual IntPoint convertFromScrollbarToContainingView(const Scrollbar*, const IntPoint&) const;
virtual IntPoint convertFromContainingViewToScrollbar(const Scrollbar*, const IntPoint&) const;
+ virtual bool shouldSuspendScrollAnimations() const;
+
+ virtual void disconnectFromPage() { m_page = 0; }
RefPtr<Scrollbar> m_vBar;
+
+ Page* m_page;
};
}
diff --git a/Source/WebCore/rendering/RenderDetails.cpp b/Source/WebCore/rendering/RenderDetails.cpp
index a1039f9..be2b435 100644
--- a/Source/WebCore/rendering/RenderDetails.cpp
+++ b/Source/WebCore/rendering/RenderDetails.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,20 +21,316 @@
#include "config.h"
#include "RenderDetails.h"
+#include "CSSStyleSelector.h"
+#include "HTMLDetailsElement.h"
+#include "HTMLNames.h"
+#include "LocalizedStrings.h"
+#include "RenderDetailsMarker.h"
+#include "RenderTextFragment.h"
+#include "RenderView.h"
+
namespace WebCore {
-RenderDetails::RenderDetails(Node* element)
- : RenderBlock(element)
+using namespace HTMLNames;
+
+RenderDetails::RenderDetails(Node* node)
+ : RenderBlock(node)
+ , m_summaryBlock(0)
+ , m_contentBlock(0)
+ , m_defaultSummaryBlock(0)
+ , m_defaultSummaryText(0)
+ , m_marker(0)
+ , m_mainSummary(0)
+{
+}
+
+void RenderDetails::destroy()
+{
+ if (m_marker) {
+ m_marker->destroy();
+ m_marker = 0;
+ }
+
+ RenderBlock::destroy();
+}
+
+RenderBlock* RenderDetails::summaryBlock()
+{
+ if (!m_summaryBlock) {
+ m_summaryBlock = createAnonymousBlock();
+ RenderBlock::addChild(m_summaryBlock, m_contentBlock);
+ }
+ return m_summaryBlock;
+}
+
+RenderBlock* RenderDetails::contentBlock()
{
+ if (!m_contentBlock) {
+ m_contentBlock = createAnonymousBlock();
+ RenderBlock::addChild(m_contentBlock);
+ }
+ return m_contentBlock;
+}
+
+void RenderDetails::addChild(RenderObject* newChild, RenderObject* beforeChild)
+{
+ if (beforeChild && beforeChild == m_mainSummary)
+ beforeChild = getRenderPosition(m_mainSummary);
+ contentBlock()->addChild(newChild, beforeChild);
+}
+
+void RenderDetails::removeChild(RenderObject* oldChild)
+{
+ if (oldChild == m_summaryBlock) {
+ RenderBlock::removeChild(oldChild);
+ m_summaryBlock = 0;
+ return;
+ }
+
+ if (oldChild == m_contentBlock) {
+ RenderBlock::removeChild(oldChild);
+ m_contentBlock = 0;
+ return;
+ }
+
+ if (oldChild == m_mainSummary && m_summaryBlock) {
+ m_summaryBlock->removeChild(m_mainSummary);
+ return;
+ }
+
+ if (m_contentBlock) {
+ m_contentBlock->removeChild(oldChild);
+ return;
+ }
+
+ ASSERT_NOT_REACHED();
+}
+
+void RenderDetails::setMarkerStyle()
+{
+ if (m_marker) {
+ RefPtr<RenderStyle> markerStyle = RenderStyle::create();
+ markerStyle->inheritFrom(style());
+ m_marker->setStyle(markerStyle.release());
+ }
}
void RenderDetails::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
RenderBlock::styleDidChange(diff, oldStyle);
+ if (m_defaultSummaryBlock) {
+ m_defaultSummaryBlock->setStyle(createSummaryStyle());
+ m_defaultSummaryText->setStyle(m_defaultSummaryBlock->style());
+ }
+
+ setMarkerStyle();
+
// Ensure that if we ended up being inline that we set our replaced flag
// so that we're treated like an inline-block.
setReplaced(isInline());
}
+RenderObject* RenderDetails::getRenderPosition(RenderObject* object)
+{
+ if (!object || !object->node())
+ return 0;
+
+ Node* element = object->node()->nextSibling();
+
+ while (element && !element->renderer())
+ element = element->nextSibling();
+
+ return element ? element->renderer() : 0;
+}
+
+void RenderDetails::markerDestroyed()
+{
+ m_marker = 0;
+}
+
+void RenderDetails::summaryDestroyed(RenderObject* summary)
+{
+ if (summary == m_mainSummary)
+ m_mainSummary = 0;
+}
+
+void RenderDetails::moveSummaryToContents()
+{
+ if (m_defaultSummaryBlock) {
+ ASSERT(!m_mainSummary);
+ m_defaultSummaryBlock->destroy();
+ m_defaultSummaryBlock = 0;
+ m_defaultSummaryText = 0;
+ return;
+ }
+
+ if (!m_mainSummary)
+ return;
+
+ m_mainSummary->remove();
+ contentBlock()->addChild(m_mainSummary, getRenderPosition(m_mainSummary));
+ m_mainSummary = 0;
+}
+
+PassRefPtr<RenderStyle> RenderDetails::createSummaryStyle()
+{
+ RefPtr<HTMLElement> summary(HTMLElement::create(summaryTag, document()));
+ return document()->styleSelector()->styleForElement(summary.get(), style(), true);
+}
+
+void RenderDetails::replaceMainSummary(RenderObject* newSummary)
+{
+ ASSERT(newSummary);
+ if (m_mainSummary == newSummary)
+ return;
+
+ moveSummaryToContents();
+ newSummary->remove();
+ summaryBlock()->addChild(newSummary);
+ m_mainSummary = newSummary;
+}
+
+void RenderDetails::createDefaultSummary()
+{
+ if (m_defaultSummaryBlock)
+ return;
+
+ moveSummaryToContents();
+
+ m_defaultSummaryBlock = summaryBlock()->createAnonymousBlock();
+ m_defaultSummaryBlock->setStyle(createSummaryStyle());
+
+ m_defaultSummaryText = new (renderArena()) RenderTextFragment(document(), defaultDetailsSummaryText().impl());
+ m_defaultSummaryText->setStyle(m_defaultSummaryBlock->style());
+ m_defaultSummaryBlock->addChild(m_defaultSummaryText);
+
+ summaryBlock()->addChild(m_defaultSummaryBlock);
+}
+
+void RenderDetails::checkMainSummary()
+{
+ if (!node() || !node()->hasTagName(detailsTag))
+ return;
+
+ Node* mainSummaryNode = static_cast<HTMLDetailsElement*>(node())->mainSummary();
+
+ if (!mainSummaryNode || !mainSummaryNode->renderer() || mainSummaryNode->renderer()->isFloatingOrPositioned())
+ createDefaultSummary();
+ else
+ replaceMainSummary(mainSummaryNode->renderer());
+
+}
+
+void RenderDetails::layout()
+{
+ ASSERT(needsLayout());
+
+ checkMainSummary();
+ ASSERT(m_summaryBlock);
+
+ if (!m_marker) {
+ m_marker = new (renderArena()) RenderDetailsMarker(this);
+ setMarkerStyle();
+ }
+ updateMarkerLocation();
+
+ RenderBlock::layout();
+
+ m_interactiveArea = m_summaryBlock->frameRect();
+
+ // FIXME: the following code will not be needed once absoluteToLocal get patched to handle flipped blocks writing modes.
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
+ case LeftToRightWritingMode:
+ break;
+ case RightToLeftWritingMode: {
+ m_interactiveArea.setX(width() - m_interactiveArea.x() - m_interactiveArea.width());
+ break;
+ }
+ case BottomToTopWritingMode: {
+ m_interactiveArea.setY(height() - m_interactiveArea.y() - m_interactiveArea.height());
+ break;
+ }
+ }
}
+
+bool RenderDetails::isOpen() const
+{
+ return node() && node()->isElementNode() ? !static_cast<Element*>(node())->getAttribute(openAttr).isNull() : false;
+}
+
+RenderObject* RenderDetails::getParentOfFirstLineBox(RenderBlock* curr)
+{
+ RenderObject* firstChild = curr->firstChild();
+ if (!firstChild)
+ return 0;
+
+ for (RenderObject* currChild = firstChild; currChild; currChild = currChild->nextSibling()) {
+ if (currChild == m_marker)
+ continue;
+
+ if (currChild->isInline() && (!currChild->isRenderInline() || curr->generatesLineBoxesForInlineChild(currChild)))
+ return curr;
+
+ if (currChild->isFloating() || currChild->isPositioned())
+ continue;
+
+ if (currChild->isTable() || !currChild->isRenderBlock() || (currChild->isBox() && toRenderBox(currChild)->isWritingModeRoot()))
+ break;
+
+ if (currChild->isDetails())
+ break;
+
+ RenderObject* lineBox = getParentOfFirstLineBox(toRenderBlock(currChild));
+ if (lineBox)
+ return lineBox;
+ }
+
+ return 0;
+}
+
+RenderObject* RenderDetails::firstNonMarkerChild(RenderObject* parent)
+{
+ RenderObject* result = parent->firstChild();
+ while (result && result->isDetailsMarker())
+ result = result->nextSibling();
+ return result;
+}
+
+void RenderDetails::updateMarkerLocation()
+{
+ // Sanity check the location of our marker.
+ if (m_marker) {
+ RenderObject* markerPar = m_marker->parent();
+ RenderObject* lineBoxParent = getParentOfFirstLineBox(m_summaryBlock);
+ if (!lineBoxParent) {
+ // If the marker is currently contained inside an anonymous box,
+ // then we are the only item in that anonymous box (since no line box
+ // parent was found). It's ok to just leave the marker where it is
+ // in this case.
+ if (markerPar && markerPar->isAnonymousBlock())
+ lineBoxParent = markerPar;
+ else
+ lineBoxParent = m_summaryBlock;
+ }
+
+ if (markerPar != lineBoxParent || m_marker->preferredLogicalWidthsDirty()) {
+ // Removing and adding the marker can trigger repainting in
+ // containers other than ourselves, so we need to disable LayoutState.
+ view()->disableLayoutState();
+ m_marker->remove();
+ if (!lineBoxParent)
+ lineBoxParent = m_summaryBlock;
+ lineBoxParent->addChild(m_marker, firstNonMarkerChild(lineBoxParent));
+
+ if (m_marker->preferredLogicalWidthsDirty())
+ m_marker->computePreferredLogicalWidths();
+
+ view()->enableLayoutState();
+ }
+ }
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/rendering/RenderDetails.h b/Source/WebCore/rendering/RenderDetails.h
index b8aebab..0b56c13 100644
--- a/Source/WebCore/rendering/RenderDetails.h
+++ b/Source/WebCore/rendering/RenderDetails.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,18 +21,65 @@
#ifndef RenderDetails_h
#define RenderDetails_h
-#include "RenderBlock.h"
+#include "RenderFlexibleBox.h"
+#include "Timer.h"
+#include <wtf/OwnPtr.h>
namespace WebCore {
+class RenderDetailsMarker;
+
class RenderDetails : public RenderBlock {
public:
explicit RenderDetails(Node*);
-private:
virtual const char* renderName() const { return "RenderDetails"; }
virtual bool isDetails() const { return true; }
+
+ bool isOpen() const;
+ IntRect interactiveArea() const { return m_interactiveArea; }
+ void markerDestroyed();
+ void summaryDestroyed(RenderObject*);
+
+private:
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+
+ virtual void addChild(RenderObject* newChild, RenderObject *beforeChild = 0);
+ virtual void removeChild(RenderObject*);
+ virtual void removeLeftoverAnonymousBlock(RenderBlock*) { }
+ virtual bool createsAnonymousWrapper() const { return true; }
+
+ virtual bool requiresForcedStyleRecalcPropagation() const { return true; }
+
+ virtual void layout();
+ virtual void destroy();
+
+ void createDefaultSummary();
+ void replaceMainSummary(RenderObject*);
+ void moveSummaryToContents();
+ void checkMainSummary();
+ RenderObject* getRenderPosition(RenderObject*);
+ PassRefPtr<RenderStyle> createSummaryStyle();
+ void setMarkerStyle();
+
+ RenderBlock* summaryBlock();
+ RenderBlock* contentBlock();
+
+ RenderObject* getParentOfFirstLineBox(RenderBlock* curr);
+ RenderObject* firstNonMarkerChild(RenderObject* parent);
+ void updateMarkerLocation();
+
+ RenderBlock* m_summaryBlock;
+ RenderBlock* m_contentBlock;
+
+ RenderObject* m_defaultSummaryBlock;
+ RenderObject* m_defaultSummaryText;
+
+ IntRect m_interactiveArea;
+
+ RenderDetailsMarker* m_marker;
+
+ RenderObject* m_mainSummary;
};
inline RenderDetails* toRenderDetails(RenderObject* object)
@@ -44,6 +91,6 @@ inline RenderDetails* toRenderDetails(RenderObject* object)
// This will catch anyone doing an unnecessary cast.
void toRenderDetails(const RenderDetails*);
-}
+} // namespace WebCore
#endif // RenderDetails_h
diff --git a/Source/WebCore/rendering/RenderDetailsMarker.cpp b/Source/WebCore/rendering/RenderDetailsMarker.cpp
index 26e49d9..e040eb3 100644
--- a/Source/WebCore/rendering/RenderDetailsMarker.cpp
+++ b/Source/WebCore/rendering/RenderDetailsMarker.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,11 +21,182 @@
#include "config.h"
#include "RenderDetailsMarker.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "PaintInfo.h"
+#include "RenderDetails.h"
+#include "RenderSummary.h"
+
namespace WebCore {
-RenderDetailsMarker::RenderDetailsMarker(Node* element)
- : RenderBlock(element)
+using namespace HTMLNames;
+
+RenderDetailsMarker::RenderDetailsMarker(RenderDetails* item)
+ : RenderBox(item->document())
+ , m_details(item)
+{
+ setInline(true);
+ setReplaced(true);
+}
+
+void RenderDetailsMarker::destroy()
+{
+ if (m_details)
+ m_details->markerDestroyed();
+
+ RenderBox::destroy();
+}
+
+int RenderDetailsMarker::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode) const
+{
+ return m_details->lineHeight(firstLine, direction, PositionOfInteriorLineBoxes);
+}
+
+int RenderDetailsMarker::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode) const
+{
+ return m_details->baselinePosition(baselineType, firstLine, direction, PositionOfInteriorLineBoxes);
+}
+
+void RenderDetailsMarker::computePreferredLogicalWidths()
+{
+ ASSERT(preferredLogicalWidthsDirty());
+
+ m_minPreferredLogicalWidth = 2 * style()->fontMetrics().ascent() / 3;
+ m_maxPreferredLogicalWidth = m_minPreferredLogicalWidth;
+
+ setPreferredLogicalWidthsDirty(false);
+}
+
+void RenderDetailsMarker::layout()
+{
+ ASSERT(needsLayout());
+
+ setLogicalWidth(minPreferredLogicalWidth());
+ setLogicalHeight(style()->fontMetrics().height());
+
+ setMarginStart(0);
+ setMarginEnd(style()->fontMetrics().ascent() - minPreferredLogicalWidth() + 1);
+
+ setNeedsLayout(false);
+}
+
+IntRect RenderDetailsMarker::getRelativeMarkerRect() const
+{
+ IntRect relativeRect;
+
+ int bulletWidth = minPreferredLogicalWidth();
+ relativeRect = IntRect((logicalWidth() - bulletWidth) / 2, (logicalHeight() - bulletWidth) / 2, bulletWidth, bulletWidth);
+
+ if (!style()->isHorizontalWritingMode()) {
+ relativeRect = relativeRect.transposedRect();
+ relativeRect.setX(width() - relativeRect.x() - relativeRect.width());
+ }
+
+ return relativeRect;
+}
+
+bool RenderDetailsMarker::isOpen() const
{
+ return m_details && m_details->isOpen();
+}
+
+static Path createPath(const FloatPoint* path)
+{
+ Path result;
+ result.moveTo(FloatPoint(path[0].x(), path[0].y()));
+ for (int i = 1; i < 4; ++i)
+ result.addLineTo(FloatPoint(path[i].x(), path[i].y()));
+ return result;
+}
+
+static Path createDownArrowPath()
+{
+ FloatPoint points[4] = { FloatPoint(0.0f, 0.07f), FloatPoint(0.5f, 0.93f), FloatPoint(1.0f, 0.07f), FloatPoint(0.0f, 0.07f) };
+ return createPath(points);
+}
+
+static Path createUpArrowPath()
+{
+ FloatPoint points[4] = { FloatPoint(0.0f, 0.93f), FloatPoint(0.5f, 0.07f), FloatPoint(1.0f, 0.93f), FloatPoint(0.0f, 0.93f) };
+ return createPath(points);
+}
+
+static Path createLeftArrowPath()
+{
+ FloatPoint points[4] = { FloatPoint(1.0f, 0.0f), FloatPoint(0.14f, 0.5f), FloatPoint(1.0f, 1.0f), FloatPoint(1.0f, 0.0f) };
+ return createPath(points);
+}
+
+static Path createRightArrowPath()
+{
+ FloatPoint points[4] = { FloatPoint(0.0f, 0.0f), FloatPoint(0.86f, 0.5f), FloatPoint(0.0f, 1.0f), FloatPoint(0.0f, 0.0f) };
+ return createPath(points);
+}
+
+RenderDetailsMarker::Orientation RenderDetailsMarker::orientation() const
+{
+ switch (style()->writingMode()) {
+ case TopToBottomWritingMode:
+ if (style()->isLeftToRightDirection())
+ return isOpen() ? Down : Right;
+ return isOpen() ? Down : Left;
+ case RightToLeftWritingMode:
+ if (style()->isLeftToRightDirection())
+ return isOpen() ? Left : Down;
+ return isOpen() ? Left : Up;
+ case LeftToRightWritingMode:
+ if (style()->isLeftToRightDirection())
+ return isOpen() ? Right : Down;
+ return isOpen() ? Right : Up;
+ case BottomToTopWritingMode:
+ if (style()->isLeftToRightDirection())
+ return isOpen() ? Up : Right;
+ return isOpen() ? Up : Left;
+ }
+ return Right;
+}
+
+Path RenderDetailsMarker::getCanonicalPath() const
+{
+ switch (orientation()) {
+ case Left: return createLeftArrowPath();
+ case Right: return createRightArrowPath();
+ case Up: return createUpArrowPath();
+ case Down: return createDownArrowPath();
+ }
+
+ return Path();
+}
+
+Path RenderDetailsMarker::getPath(const IntPoint& origin) const
+{
+ IntRect rect = getRelativeMarkerRect();
+ Path result = getCanonicalPath();
+ result.transform(AffineTransform().scale(rect.width()));
+ result.translate(FloatSize(origin.x() + rect.x(), origin.y() + rect.y()));
+ return result;
+}
+
+void RenderDetailsMarker::paint(PaintInfo& paintInfo, int tx, int ty)
+{
+ if (paintInfo.phase != PaintPhaseForeground || style()->visibility() != VISIBLE)
+ return;
+
+ IntPoint boxOrigin(tx + x(), ty + y());
+ IntRect overflowRect(visualOverflowRect());
+ overflowRect.move(boxOrigin.x(), boxOrigin.y());
+ overflowRect.inflate(maximalOutlineSize(paintInfo.phase));
+
+ if (!paintInfo.rect.intersects(overflowRect))
+ return;
+
+ const Color color(style()->visitedDependentColor(CSSPropertyColor));
+ paintInfo.context->setStrokeColor(color, style()->colorSpace());
+ paintInfo.context->setStrokeStyle(SolidStroke);
+ paintInfo.context->setStrokeThickness(1.0f);
+ paintInfo.context->setFillColor(color, style()->colorSpace());
+
+ paintInfo.context->fillPath(getPath(boxOrigin));
}
}
diff --git a/Source/WebCore/rendering/RenderDetailsMarker.h b/Source/WebCore/rendering/RenderDetailsMarker.h
index 08bdbd8..de8f60b 100644
--- a/Source/WebCore/rendering/RenderDetailsMarker.h
+++ b/Source/WebCore/rendering/RenderDetailsMarker.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,25 +21,52 @@
#ifndef RenderDetailsMarker_h
#define RenderDetailsMarker_h
-#include "RenderBlock.h"
+#include "RenderBox.h"
namespace WebCore {
-class RenderDetailsMarker : public RenderBlock {
+class RenderDetails;
+
+class RenderDetailsMarker : public RenderBox {
public:
- explicit RenderDetailsMarker(Node*);
+ RenderDetailsMarker(RenderDetails*);
+
+ enum Orientation { Up, Down, Left, Right };
+
+ Orientation orientation() const;
+
+ virtual void computePreferredLogicalWidths();
+ virtual void destroy();
private:
virtual const char* renderName() const { return "RenderDetailsMarker"; }
virtual bool isDetailsMarker() const { return true; }
+ virtual void paint(PaintInfo&, int tx, int ty);
+ virtual void layout();
+ virtual int lineHeight(bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
+ virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
+
+ IntRect getRelativeMarkerRect() const;
+
+ bool isOpen() const;
+ Path getCanonicalPath() const;
+ Path getPath(const IntPoint& origin) const;
+
+ RenderDetails* m_details;
};
inline RenderDetailsMarker* toRenderDetailsMarker(RenderObject* object)
{
- ASSERT(!object || object->isDetails());
+ ASSERT(!object || object->isDetailsMarker());
return static_cast<RenderDetailsMarker*>(object);
}
+inline const RenderDetailsMarker* toRenderDetailsMarker(const RenderObject* object)
+{
+ ASSERT(!object || object->isDetailsMarker());
+ return static_cast<const RenderDetailsMarker*>(object);
+}
+
// This will catch anyone doing an unnecessary cast.
void toRenderDetailsMarker(const RenderDetailsMarker*);
diff --git a/Source/WebCore/rendering/RenderFlexibleBox.cpp b/Source/WebCore/rendering/RenderFlexibleBox.cpp
index 8241dcd..4d97da0 100644
--- a/Source/WebCore/rendering/RenderFlexibleBox.cpp
+++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp
@@ -214,7 +214,7 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, int /*pageHeight FIXM
{
ASSERT(needsLayout());
- if (!relayoutChildren && layoutOnlyPositionedObjects())
+ if (!relayoutChildren && simplifiedLayout())
return;
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
@@ -421,13 +421,11 @@ void RenderFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
if (child->isPositioned()) {
child->containingBlock()->insertPositionedObject(child);
RenderLayer* childLayer = child->layer();
- if (child->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode()))
- childLayer->setStaticInlinePosition(xPos);
- if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode())) {
- if (childLayer->staticBlockPosition() != yPos) {
- childLayer->setStaticBlockPosition(yPos);
+ childLayer->setStaticInlinePosition(xPos);
+ if (childLayer->staticBlockPosition() != yPos) {
+ childLayer->setStaticBlockPosition(yPos);
+ if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
child->setChildNeedsLayout(true, false);
- }
}
child = iterator.next();
continue;
@@ -684,17 +682,11 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
if (child->isPositioned()) {
child->containingBlock()->insertPositionedObject(child);
RenderLayer* childLayer = child->layer();
- if (child->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode())) {
- if (style()->isLeftToRightDirection())
- childLayer->setStaticInlinePosition(borderLeft() + paddingLeft());
- else
- childLayer->setStaticInlinePosition(borderRight() + paddingRight());
- }
- if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode())) {
- if (childLayer->staticBlockPosition() != height()) {
- childLayer->setStaticBlockPosition(height());
+ childLayer->setStaticInlinePosition(borderStart() + paddingStart());
+ if (childLayer->staticBlockPosition() != height()) {
+ childLayer->setStaticBlockPosition(height());
+ if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
child->setChildNeedsLayout(true, false);
- }
}
child = iterator.next();
continue;
diff --git a/Source/WebCore/rendering/RenderFullScreen.cpp b/Source/WebCore/rendering/RenderFullScreen.cpp
index cc53a6e..a685064 100644
--- a/Source/WebCore/rendering/RenderFullScreen.cpp
+++ b/Source/WebCore/rendering/RenderFullScreen.cpp
@@ -64,7 +64,7 @@ PassRefPtr<RenderStyle> RenderFullScreen::createFullScreenStyle()
fullscreenStyle->setBackgroundColor(Color::black);
- return fullscreenStyle;
+ return fullscreenStyle.release();
}
#endif
diff --git a/Source/WebCore/rendering/RenderInline.cpp b/Source/WebCore/rendering/RenderInline.cpp
index 234d63c..3a27307 100644
--- a/Source/WebCore/rendering/RenderInline.cpp
+++ b/Source/WebCore/rendering/RenderInline.cpp
@@ -201,8 +201,7 @@ void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderOb
// inline into continuations. This involves creating an anonymous block box to hold
// |newChild|. We then make that block box a continuation of this inline. We take all of
// the children after |beforeChild| and put them in a clone of this object.
- RefPtr<RenderStyle> newStyle = RenderStyle::create();
- newStyle->inheritFrom(style());
+ RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
newStyle->setDisplay(BLOCK);
RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
@@ -485,29 +484,21 @@ static int computeMargin(const RenderInline* renderer, const Length& margin)
int RenderInline::marginLeft() const
{
- if (!style()->isHorizontalWritingMode())
- return 0;
return computeMargin(this, style()->marginLeft());
}
int RenderInline::marginRight() const
{
- if (!style()->isHorizontalWritingMode())
- return 0;
return computeMargin(this, style()->marginRight());
}
int RenderInline::marginTop() const
{
- if (style()->isHorizontalWritingMode())
- return 0;
return computeMargin(this, style()->marginTop());
}
int RenderInline::marginBottom() const
{
- if (style()->isHorizontalWritingMode())
- return 0;
return computeMargin(this, style()->marginBottom());
}
@@ -521,6 +512,16 @@ int RenderInline::marginEnd() const
return computeMargin(this, style()->marginEnd());
}
+int RenderInline::marginBefore() const
+{
+ return computeMargin(this, style()->marginBefore());
+}
+
+int RenderInline::marginAfter() const
+{
+ return computeMargin(this, style()->marginAfter());
+}
+
const char* RenderInline::renderName() const
{
if (isRelPositioned())
diff --git a/Source/WebCore/rendering/RenderInline.h b/Source/WebCore/rendering/RenderInline.h
index 18b4a3c..08ac002 100644
--- a/Source/WebCore/rendering/RenderInline.h
+++ b/Source/WebCore/rendering/RenderInline.h
@@ -42,8 +42,8 @@ public:
virtual int marginRight() const;
virtual int marginTop() const;
virtual int marginBottom() const;
- virtual int marginBefore() const { return 0; }
- virtual int marginAfter() const { return 0; }
+ virtual int marginBefore() const;
+ virtual int marginAfter() const;
virtual int marginStart() const;
virtual int marginEnd() const;
diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp
index bc0d440..3c6bc31 100644
--- a/Source/WebCore/rendering/RenderLayer.cpp
+++ b/Source/WebCore/rendering/RenderLayer.cpp
@@ -178,6 +178,7 @@ RenderLayer::RenderLayer(RenderBoxModelObject* renderer)
, m_hasCompositingDescendant(false)
, m_mustOverlapCompositedLayers(false)
#endif
+ , m_containsDirtyOverlayScrollbars(false)
#if ENABLE(ANDROID_OVERFLOW_SCROLL)
, m_hasOverflowScroll(false)
#endif
@@ -194,6 +195,13 @@ RenderLayer::RenderLayer(RenderBoxModelObject* renderer)
m_visibleContentStatusDirty = false;
m_hasVisibleContent = renderer->style()->visibility() == VISIBLE;
}
+
+ if (Frame* frame = renderer->frame()) {
+ if (Page* page = frame->page()) {
+ m_page = page;
+ m_page->addScrollableArea(this);
+ }
+ }
}
RenderLayer::~RenderLayer()
@@ -203,6 +211,9 @@ RenderLayer::~RenderLayer()
frame->eventHandler()->resizeLayerDestroyed();
}
+ if (m_page)
+ m_page->removeScrollableArea(this);
+
destroyScrollbar(HorizontalScrollbar);
destroyScrollbar(VerticalScrollbar);
@@ -268,19 +279,6 @@ bool RenderLayer::canRender3DTransforms() const
void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags, IntPoint* cachedOffset)
{
- if (flags & DoFullRepaint) {
- renderer()->repaint();
-#if USE(ACCELERATED_COMPOSITING)
- flags &= ~CheckForRepaint;
- // We need the full repaint to propagate to child layers if we are hardware compositing.
- if (!compositor()->inCompositingMode())
- flags &= ~DoFullRepaint;
-#else
- flags &= ~(CheckForRepaint | DoFullRepaint);
-#endif
- }
-
-
updateLayerPosition(); // For relpositioned layers or non-positioned layers,
// we need to keep in sync, since we may have shifted relative
// to our parent layer.
@@ -1121,6 +1119,7 @@ void RenderLayer::removeOnlyThisLayer()
RenderLayer* next = current->nextSibling();
removeChild(current);
parent->addChild(current, nextSib);
+ current->setNeedsFullRepaint();
current->updateLayerPositions(); // Depends on hasLayer() already being false for proper layout.
current = next;
}
@@ -1806,6 +1805,19 @@ int RenderLayer::visibleWidth() const
return m_width;
}
+bool RenderLayer::shouldSuspendScrollAnimations() const
+{
+ RenderView* view = renderer()->view();
+ if (!view)
+ return true;
+ return view->frameView()->shouldSuspendScrollAnimations();
+}
+
+IntPoint RenderLayer::currentMousePosition() const
+{
+ return renderer()->frame() ? renderer()->frame()->eventHandler()->currentMousePosition() : IntPoint();
+}
+
IntSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const
{
RenderBox* box = renderBox();
@@ -1915,16 +1927,16 @@ void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
#endif
}
-int RenderLayer::verticalScrollbarWidth() const
+int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
{
- if (!m_vBar || m_vBar->isOverlayScrollbar())
+ if (!m_vBar || (m_vBar->isOverlayScrollbar() && relevancy == IgnoreOverlayScrollbarSize))
return 0;
return m_vBar->width();
}
-int RenderLayer::horizontalScrollbarHeight() const
+int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
{
- if (!m_hBar || m_hBar->isOverlayScrollbar())
+ if (!m_hBar || (m_hBar->isOverlayScrollbar() && relevancy == IgnoreOverlayScrollbarSize))
return 0;
return m_hBar->height();
}
@@ -2214,16 +2226,36 @@ void RenderLayer::updateScrollInfoAfterLayout()
#endif
}
-void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
+void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty, const IntRect& damageRect, bool paintingOverlayControls)
{
// Don't do anything if we have no overflow.
if (!renderer()->hasOverflowClip())
return;
-
+
+ // Overlay scrollbars paint in a second pass through the layer tree so that they will paint
+ // on top of everything else. If this is the normal painting pass, paintingOverlayControls
+ // will be false, and we should just tell the root layer that there are overlay scrollbars
+ // that need to be painted. That will cause the second pass through the layer tree to run,
+ // and we'll paint the scrollbars then. In the meantime, cache tx and ty so that the
+ // second pass doesn't need to re-enter the RenderTree to get it right.
+ if (hasOverlayScrollbars() && !paintingOverlayControls) {
+ RenderLayer* rootLayer = renderer()->view()->layer();
+ rootLayer->setContainsDirtyOverlayScrollbars(true);
+ m_cachedOverlayScrollbarOffset = IntPoint(tx, ty);
+ return;
+ }
+
+ int offsetX = tx;
+ int offsetY = ty;
+ if (paintingOverlayControls) {
+ offsetX = m_cachedOverlayScrollbarOffset.x();
+ offsetY = m_cachedOverlayScrollbarOffset.y();
+ }
+
// Move the scrollbar widgets if necessary. We normally move and resize widgets during layout, but sometimes
// widgets can move without layout occurring (most notably when you scroll a document that
// contains fixed positioned elements).
- positionOverflowControls(tx, ty);
+ positionOverflowControls(offsetX, offsetY);
// Now that we're sure the scrollbars are in the right place, paint them.
if (m_hBar)
@@ -2233,10 +2265,10 @@ void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty
// We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the
// edge of the box.
- paintScrollCorner(context, tx, ty, damageRect);
+ paintScrollCorner(context, offsetX, offsetY, damageRect);
// Paint our resizer last, since it sits on top of the scroll corner.
- paintResizer(context, tx, ty, damageRect);
+ paintResizer(context, offsetX, offsetY, damageRect);
}
void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
@@ -2258,8 +2290,11 @@ void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, co
m_scrollCorner->paintIntoRect(context, tx, ty, absRect);
return;
}
-
- context->fillRect(absRect, Color::white, box->style()->colorSpace());
+
+ // We don't want to paint white if we have overlay scrollbars, since we need
+ // to see what is behind it.
+ if (!hasOverlayScrollbars())
+ context->fillRect(absRect, Color::white, box->style()->colorSpace());
}
void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
@@ -2376,6 +2411,15 @@ void RenderLayer::paint(GraphicsContext* p, const IntRect& damageRect, PaintBeha
it->first->setOverlapTestResult(false);
}
+void RenderLayer::paintOverlayScrollbars(GraphicsContext* p, const IntRect& damageRect, PaintBehavior paintBehavior, RenderObject *paintingRoot)
+{
+ if (!m_containsDirtyOverlayScrollbars)
+ return;
+ paintLayer(this, p, damageRect, paintBehavior, paintingRoot, 0, PaintLayerHaveTransparency | PaintLayerTemporaryClipRects
+ | PaintLayerPaintingOverlayScrollbars);
+ m_containsDirtyOverlayScrollbars = false;
+}
+
static void setClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect)
{
if (paintDirtyRect == clipRect)
@@ -2526,9 +2570,11 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
if (overlapTestRequests && isSelfPaintingLayer())
performOverlapTests(*overlapTestRequests, rootLayer, this);
+ bool paintingOverlayScrollbars = paintFlags & PaintLayerPaintingOverlayScrollbars;
+
// We want to paint our layer, but only if we intersect the damage rect.
bool shouldPaint = intersectsDamageRect(layerBounds, damageRect, rootLayer) && m_hasVisibleContent && isSelfPaintingLayer();
- if (shouldPaint && !selectionOnly && !damageRect.isEmpty()) {
+ if (shouldPaint && !selectionOnly && !damageRect.isEmpty() && !paintingOverlayScrollbars) {
// Begin transparency layers lazily now that we know we have to paint something.
if (haveTransparency)
beginTransparencyLayers(p, rootLayer, paintBehavior);
@@ -2549,7 +2595,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
paintList(m_negZOrderList, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags);
// Now establish the appropriate clip and paint our child RenderObjects.
- if (shouldPaint && !clipRectToApply.isEmpty()) {
+ if (shouldPaint && !clipRectToApply.isEmpty() && !paintingOverlayScrollbars) {
// Begin transparency layers lazily now that we know we have to paint something.
if (haveTransparency)
beginTransparencyLayers(p, rootLayer, paintBehavior);
@@ -2574,7 +2620,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
restoreClip(p, paintDirtyRect, clipRectToApply);
}
- if (!outlineRect.isEmpty() && isSelfPaintingLayer()) {
+ if (!outlineRect.isEmpty() && isSelfPaintingLayer() && !paintingOverlayScrollbars) {
// Paint our own outline
PaintInfo paintInfo(p, outlineRect, PaintPhaseSelfOutline, false, paintingRootForRenderer, 0);
setClip(p, paintDirtyRect, outlineRect);
@@ -2588,7 +2634,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
// Now walk the sorted list of children with positive z-indices.
paintList(m_posZOrderList, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags);
- if (renderer()->hasMask() && shouldPaint && !selectionOnly && !damageRect.isEmpty()) {
+ if (renderer()->hasMask() && shouldPaint && !selectionOnly && !damageRect.isEmpty() && !paintingOverlayScrollbars) {
setClip(p, paintDirtyRect, damageRect);
// Paint the mask.
@@ -2599,6 +2645,12 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
restoreClip(p, paintDirtyRect, damageRect);
}
+ if (paintingOverlayScrollbars) {
+ setClip(p, paintDirtyRect, damageRect);
+ paintOverflowControls(p, tx, ty, damageRect, true);
+ restoreClip(p, paintDirtyRect, damageRect);
+ }
+
// End our transparency layer
if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) {
p->endTransparencyLayer();
diff --git a/Source/WebCore/rendering/RenderLayer.h b/Source/WebCore/rendering/RenderLayer.h
index 7dddbc8..17ba99e 100644
--- a/Source/WebCore/rendering/RenderLayer.h
+++ b/Source/WebCore/rendering/RenderLayer.h
@@ -282,8 +282,8 @@ public:
Scrollbar* horizontalScrollbar() const { return m_hBar.get(); }
Scrollbar* verticalScrollbar() const { return m_vBar.get(); }
- int verticalScrollbarWidth() const;
- int horizontalScrollbarHeight() const;
+ int verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy = IgnoreOverlayScrollbarSize) const;
+ int horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy = IgnoreOverlayScrollbarSize) const;
bool hasOverflowControls() const;
#if ENABLE(ANDROID_OVERFLOW_SCROLL)
@@ -295,7 +295,7 @@ public:
bool hitTestOverflowControls(HitTestResult&, const IntPoint& localPoint);
IntSize offsetFromResizeCorner(const IntPoint& absolutePoint) const;
- void paintOverflowControls(GraphicsContext*, int tx, int ty, const IntRect& damageRect);
+ void paintOverflowControls(GraphicsContext*, int tx, int ty, const IntRect& damageRect, bool paintingOverlayControls = false);
void paintScrollCorner(GraphicsContext*, int tx, int ty, const IntRect& damageRect);
void paintResizer(GraphicsContext*, int tx, int ty, const IntRect& damageRect);
@@ -327,14 +327,13 @@ public:
void updateLayerPosition();
enum UpdateLayerPositionsFlag {
- DoFullRepaint = 1,
- CheckForRepaint = 1 << 1,
- IsCompositingUpdateRoot = 1 << 2,
- UpdateCompositingLayers = 1 << 3,
- UpdatePagination = 1 << 4
+ CheckForRepaint = 1,
+ IsCompositingUpdateRoot = 1 << 1,
+ UpdateCompositingLayers = 1 << 2,
+ UpdatePagination = 1 << 3
};
typedef unsigned UpdateLayerPositionsFlags;
- void updateLayerPositions(UpdateLayerPositionsFlags = DoFullRepaint | IsCompositingUpdateRoot | UpdateCompositingLayers, IntPoint* cachedOffset = 0);
+ void updateLayerPositions(UpdateLayerPositionsFlags = CheckForRepaint | IsCompositingUpdateRoot | UpdateCompositingLayers, IntPoint* cachedOffset = 0);
void updateTransform();
@@ -409,6 +408,7 @@ public:
// layers that intersect the point from front to back.
void paint(GraphicsContext*, const IntRect& damageRect, PaintBehavior = PaintBehaviorNormal, RenderObject* paintingRoot = 0);
bool hitTest(const HitTestRequest&, HitTestResult&);
+ void paintOverlayScrollbars(GraphicsContext*, const IntRect& damageRect, PaintBehavior, RenderObject* paintingRoot);
// This method figures out our layerBounds in coordinates relative to
// |rootLayer}. It also computes our background and foreground clip rects
@@ -491,6 +491,9 @@ public:
bool paintsWithTransform(PaintBehavior) const;
+ bool containsDirtyOverlayScrollbars() const { return m_containsDirtyOverlayScrollbars; }
+ void setContainsDirtyOverlayScrollbars(bool dirtyScrollbars) { m_containsDirtyOverlayScrollbars = dirtyScrollbars; }
+
private:
// The normal operator new is disallowed on all render objects.
void* operator new(size_t) throw();
@@ -513,7 +516,8 @@ private:
PaintLayerHaveTransparency = 1,
PaintLayerAppliedTransform = 1 << 1,
PaintLayerTemporaryClipRects = 1 << 2,
- PaintLayerPaintingReflection = 1 << 3
+ PaintLayerPaintingReflection = 1 << 3,
+ PaintLayerPaintingOverlayScrollbars = 1 << 4
};
typedef unsigned PaintLayerFlags;
@@ -573,6 +577,10 @@ private:
virtual IntSize contentsSize() const;
virtual int visibleHeight() const;
virtual int visibleWidth() const;
+ virtual IntPoint currentMousePosition() const;
+ virtual bool shouldSuspendScrollAnimations() const;
+
+ virtual void disconnectFromPage() { m_page = 0; }
// NOTE: This should only be called by the overriden setScrollOffset from ScrollableArea.
void scrollTo(int x, int y);
@@ -666,18 +674,6 @@ protected:
int m_scrollX;
int m_scrollY;
- // There are 8 possible combinations of writing mode and direction. Scroll origin (and its corresponding left/top overflow)
- // will be non-zero in the x or y axis if there is any reversed direction or writing-mode. The combinations are:
- // writing-mode / direction scrollOrigin.x() set scrollOrigin.y() set
- // horizontal-tb / ltr NO NO
- // horizontal-tb / rtl YES NO
- // horizontal-bt / ltr NO YES
- // horizontal-bt / rtl YES YES
- // vertical-lr / ltr NO NO
- // vertical-lr / rtl NO YES
- // vertical-rl / ltr YES NO
- // vertical-rl / rtl YES YES
- IntPoint m_scrollOrigin;
int m_scrollLeftOverflow;
int m_scrollTopOverflow;
@@ -737,10 +733,14 @@ protected:
bool m_hasCompositingDescendant : 1;
bool m_mustOverlapCompositedLayers : 1;
#endif
+
+ bool m_containsDirtyOverlayScrollbars : 1;
#if ENABLE(ANDROID_OVERFLOW_SCROLL)
bool m_hasOverflowScroll : 1;
#endif
+ IntPoint m_cachedOverlayScrollbarOffset;
+
RenderMarquee* m_marquee; // Used by layers with overflow:marquee
// Cached normal flow values for absolute positioned elements with static left/top values.
@@ -762,6 +762,8 @@ private:
#if USE(ACCELERATED_COMPOSITING)
OwnPtr<RenderLayerBacking> m_backing;
#endif
+
+ Page* m_page;
};
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderLayerBacking.cpp b/Source/WebCore/rendering/RenderLayerBacking.cpp
index bda34ee..26a10dd 100644
--- a/Source/WebCore/rendering/RenderLayerBacking.cpp
+++ b/Source/WebCore/rendering/RenderLayerBacking.cpp
@@ -380,6 +380,7 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
IntSize oldOffsetFromRenderer = m_graphicsLayer->offsetFromRenderer();
m_graphicsLayer->setOffsetFromRenderer(localCompositingBounds.location() - IntPoint());
+
// If the compositing layer offset changes, we need to repaint.
if (oldOffsetFromRenderer != m_graphicsLayer->offsetFromRenderer())
m_graphicsLayer->setNeedsDisplay();
@@ -449,10 +450,9 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
FloatPoint foregroundPosition;
FloatSize foregroundSize = newSize;
IntSize foregroundOffset = m_graphicsLayer->offsetFromRenderer();
- // If we have a clipping layer (which clips descendants), then the foreground layer is a child of it,
- // so that it gets correctly sorted with children. In that case, position relative to the clipping layer.
if (m_clippingLayer) {
- foregroundPosition = FloatPoint() + (localCompositingBounds.location() - clippingBox.location());
+ // If we have a clipping layer (which clips descendants), then the foreground layer is a child of it,
+ // so that it gets correctly sorted with children. In that case, position relative to the clipping layer.
foregroundSize = FloatSize(clippingBox.size());
foregroundOffset = clippingBox.location() - IntPoint();
}
@@ -930,18 +930,6 @@ IntRect RenderLayerBacking::contentsBox() const
return contentsRect;
}
-// Map the given point from coordinates in the GraphicsLayer to RenderLayer coordinates.
-FloatPoint RenderLayerBacking::graphicsLayerToContentsCoordinates(const GraphicsLayer* graphicsLayer, const FloatPoint& point)
-{
- return point + FloatSize(graphicsLayer->offsetFromRenderer());
-}
-
-// Map the given point from coordinates in the RenderLayer to GraphicsLayer coordinates.
-FloatPoint RenderLayerBacking::contentsToGraphicsLayerCoordinates(const GraphicsLayer* graphicsLayer, const FloatPoint& point)
-{
- return point - FloatSize(graphicsLayer->offsetFromRenderer());
-}
-
bool RenderLayerBacking::paintingGoesToWindow() const
{
if (m_owningLayer->isRootLayer())
@@ -966,21 +954,21 @@ void RenderLayerBacking::setContentsNeedDisplay()
void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r)
{
if (m_graphicsLayer && m_graphicsLayer->drawsContent()) {
- FloatPoint dirtyOrigin = contentsToGraphicsLayerCoordinates(m_graphicsLayer.get(), FloatPoint(r.x(), r.y()));
- FloatRect dirtyRect(dirtyOrigin, r.size());
- FloatRect bounds(FloatPoint(), m_graphicsLayer->size());
- if (bounds.intersects(dirtyRect))
- m_graphicsLayer->setNeedsDisplayInRect(dirtyRect);
+ IntRect layerDirtyRect = r;
+ layerDirtyRect.move(-m_graphicsLayer->offsetFromRenderer());
+ m_graphicsLayer->setNeedsDisplayInRect(layerDirtyRect);
}
if (m_foregroundLayer && m_foregroundLayer->drawsContent()) {
- // FIXME: do incremental repaint
- m_foregroundLayer->setNeedsDisplay();
+ IntRect layerDirtyRect = r;
+ layerDirtyRect.move(-m_foregroundLayer->offsetFromRenderer());
+ m_foregroundLayer->setNeedsDisplayInRect(layerDirtyRect);
}
if (m_maskLayer && m_maskLayer->drawsContent()) {
- // FIXME: do incremental repaint
- m_maskLayer->setNeedsDisplay();
+ IntRect layerDirtyRect = r;
+ layerDirtyRect.move(-m_maskLayer->offsetFromRenderer());
+ m_maskLayer->setNeedsDisplayInRect(layerDirtyRect);
}
}
@@ -1123,32 +1111,27 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext*
}
// Up-call from compositing layer drawing callback.
-void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const IntRect& clip)
+void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const IntRect& clip)
{
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.
- IntRect enclosingBBox = compositedBounds();
+ IntSize offset = graphicsLayer->offsetFromRenderer();
+ context.translate(-offset);
+
+ IntRect clipRect(clip);
+ clipRect.move(offset);
+
+ // The dirtyRect is in the coords of the painting root.
+ IntRect dirtyRect = compositedBounds();
#if ENABLE(ANDROID_OVERFLOW_SCROLL)
// If we encounter a scrollable layer, layers inside the scrollable layer
// will need their entire content recorded.
if (m_owningLayer->hasOverflowParent())
- enclosingBBox.setSize(clip.size());
+ dirtyRect.setSize(clip.size());
#endif
-
- IntRect clipRect(clip);
-
- // Set up the coordinate space to be in the layer's rendering coordinates.
- context.translate(-enclosingBBox.x(), -enclosingBBox.y());
-
- // Offset the clip.
- clipRect.move(enclosingBBox.x(), enclosingBBox.y());
-
- // The dirtyRect is in the coords of the painting root.
- IntRect dirtyRect = enclosingBBox;
dirtyRect.intersect(clipRect);
+ // We have to use the same root as for hit testing, because both methods can compute and cache clipRects.
paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase, renderer());
InspectorInstrumentation::didPaint(cookie);
diff --git a/Source/WebCore/rendering/RenderLayerBacking.h b/Source/WebCore/rendering/RenderLayerBacking.h
index 726b777..8f0927d 100644
--- a/Source/WebCore/rendering/RenderLayerBacking.h
+++ b/Source/WebCore/rendering/RenderLayerBacking.h
@@ -123,9 +123,6 @@ public:
void updateAfterWidgetResize();
- FloatPoint graphicsLayerToContentsCoordinates(const GraphicsLayer*, const FloatPoint&);
- FloatPoint contentsToGraphicsLayerCoordinates(const GraphicsLayer*, const FloatPoint&);
-
// GraphicsLayerClient interface
virtual void notifyAnimationStarted(const GraphicsLayer*, double startTime);
virtual void notifySyncRequired(const GraphicsLayer*);
diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp
index 4ab274f..6542ffd 100644
--- a/Source/WebCore/rendering/RenderLayerCompositor.cpp
+++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp
@@ -109,11 +109,22 @@ RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView)
, m_compositing(false)
, m_compositingLayersNeedRebuild(false)
, m_flushingLayers(false)
+ , m_forceCompositingMode(false)
, m_rootLayerAttachment(RootLayerUnattached)
#if PROFILE_LAYER_REBUILD
, m_rootLayerUpdateCount(0)
#endif // PROFILE_LAYER_REBUILD
{
+ Settings* settings = m_renderView->document()->settings();
+
+ // Even when forcing compositing mode, ignore child frames, or this will trigger
+ // layer creation from the enclosing RenderIFrame.
+ ASSERT(m_renderView->document()->frame());
+ if (settings && settings->forceCompositingMode() && settings->acceleratedCompositingEnabled()
+ && !m_renderView->document()->frame()->tree()->parent()) {
+ m_forceCompositingMode = true;
+ enableCompositingMode();
+ }
}
RenderLayerCompositor::~RenderLayerCompositor()
@@ -439,7 +450,7 @@ IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* laye
if (layer->renderer()->isRoot()) {
// If the root layer becomes composited (e.g. because some descendant with negative z-index is composited),
// then it has to be big enough to cover the viewport in order to display the background. This is akin
- // to the code in RenderBox::paintRootBoxDecorations().
+ // to the code in RenderBox::paintRootBoxFillLayers().
if (m_renderView->frameView()) {
int rw = m_renderView->frameView()->contentsWidth();
int rh = m_renderView->frameView()->contentsHeight();
@@ -770,7 +781,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O
// If we're back at the root, and no other layers need to be composited, and the root layer itself doesn't need
// to be composited, then we can drop out of compositing mode altogether.
- if (layer->isRootLayer() && !childState.m_subtreeIsCompositing && !requiresCompositingLayer(layer)) {
+ if (layer->isRootLayer() && !childState.m_subtreeIsCompositing && !requiresCompositingLayer(layer) && !m_forceCompositingMode) {
enableCompositingMode(false);
willBeComposited = false;
}
@@ -939,7 +950,7 @@ void RenderLayerCompositor::frameViewDidScroll(const IntPoint& scrollPosition)
m_scrollLayer->setPosition(FloatPoint(-scrollPosition.x(), -scrollPosition.y()));
}
-String RenderLayerCompositor::layerTreeAsText()
+String RenderLayerCompositor::layerTreeAsText(bool showDebugInfo)
{
if (compositingLayerUpdatePending())
updateCompositingLayers();
@@ -949,7 +960,7 @@ String RenderLayerCompositor::layerTreeAsText()
// We skip dumping the scroll and clip layers to keep layerTreeAsText output
// similar between platforms.
- return m_rootPlatformLayer->layerTreeAsText();
+ return m_rootPlatformLayer->layerTreeAsText(showDebugInfo ? LayerTreeAsTextDebug : LayerTreeAsTextBehaviorNormal);
}
RenderLayerCompositor* RenderLayerCompositor::iframeContentsCompositor(RenderIFrame* renderer)
diff --git a/Source/WebCore/rendering/RenderLayerCompositor.h b/Source/WebCore/rendering/RenderLayerCompositor.h
index 1cf9ea9..c3deb3f 100644
--- a/Source/WebCore/rendering/RenderLayerCompositor.h
+++ b/Source/WebCore/rendering/RenderLayerCompositor.h
@@ -175,7 +175,7 @@ public:
void frameViewDidChangeSize(const IntPoint& contentsOffset = IntPoint());
void frameViewDidScroll(const IntPoint& = IntPoint());
- String layerTreeAsText();
+ String layerTreeAsText(bool showDebugInfo = false);
// These are named to avoid conflicts with the functions in GraphicsLayerClient
// These return the actual internal variables.
@@ -277,6 +277,7 @@ private:
bool m_compositing;
bool m_compositingLayersNeedRebuild;
bool m_flushingLayers;
+ bool m_forceCompositingMode;
RootLayerAttachment m_rootLayerAttachment;
diff --git a/Source/WebCore/rendering/RenderListBox.cpp b/Source/WebCore/rendering/RenderListBox.cpp
index 4457285..ab3a832 100644
--- a/Source/WebCore/rendering/RenderListBox.cpp
+++ b/Source/WebCore/rendering/RenderListBox.cpp
@@ -82,11 +82,17 @@ RenderListBox::RenderListBox(Element* element)
, m_optionsWidth(0)
, m_indexOffset(0)
{
+ if (Page* page = frame()->page()) {
+ m_page = page;
+ m_page->addScrollableArea(this);
+ }
}
RenderListBox::~RenderListBox()
{
setHasVerticalScrollbar(false);
+ if (m_page)
+ m_page->removeScrollableArea(this);
}
void RenderListBox::updateFromElement()
@@ -316,6 +322,25 @@ void RenderListBox::paintScrollbar(PaintInfo& paintInfo, int tx, int ty)
}
}
+static IntSize itemOffsetForAlignment(TextRun textRun, RenderStyle* itemStyle, Font itemFont, IntRect itemBoudingBox)
+{
+ ETextAlign actualAlignment = itemStyle->textAlign();
+ // FIXME: Firefox doesn't respect JUSTIFY. Should we?
+ if (actualAlignment == TAAUTO || actualAlignment == JUSTIFY)
+ actualAlignment = itemStyle->isLeftToRightDirection() ? LEFT : RIGHT;
+
+ IntSize offset = IntSize(0, itemFont.fontMetrics().ascent());
+ if (actualAlignment == RIGHT || actualAlignment == WEBKIT_RIGHT) {
+ float textWidth = itemFont.width(textRun);
+ offset.setWidth(itemBoudingBox.width() - textWidth - optionsSpacingHorizontal);
+ } else if (actualAlignment == CENTER || actualAlignment == WEBKIT_CENTER) {
+ float textWidth = itemFont.width(textRun);
+ offset.setWidth((itemBoudingBox.width() - textWidth) / 2);
+ } else
+ offset.setWidth(optionsSpacingHorizontal);
+ return offset;
+}
+
void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, int listIndex)
{
SelectElement* select = toSelectElement(static_cast<Element*>(node()));
@@ -323,19 +348,18 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in
Element* element = listItems[listIndex];
OptionElement* optionElement = toOptionElement(element);
+ RenderStyle* itemStyle = element->renderStyle();
+ if (!itemStyle)
+ itemStyle = style();
+
+ if (itemStyle->visibility() == HIDDEN)
+ return;
+
String itemText;
if (optionElement)
itemText = optionElement->textIndentedToRespectGroupLabel();
else if (OptionGroupElement* optionGroupElement = toOptionGroupElement(element))
- itemText = optionGroupElement->groupLabelText();
-
- // Determine where the item text should be placed
- IntRect r = itemBoundingBoxRect(tx, ty, listIndex);
- r.move(optionsSpacingHorizontal, style()->fontMetrics().ascent());
-
- RenderStyle* itemStyle = element->renderStyle();
- if (!itemStyle)
- itemStyle = style();
+ itemText = optionGroupElement->groupLabelText();
Color textColor = element->renderStyle() ? element->renderStyle()->visitedDependentColor(CSSPropertyColor) : style()->visitedDependentColor(CSSPropertyColor);
if (optionElement && optionElement->selected()) {
@@ -349,7 +373,13 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in
ColorSpace colorSpace = itemStyle->colorSpace();
paintInfo.context->setFillColor(textColor, colorSpace);
+ unsigned length = itemText.length();
+ const UChar* string = itemText.characters();
+ TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, !itemStyle->isLeftToRightDirection(), itemStyle->unicodeBidi() == Override);
Font itemFont = style()->font();
+ IntRect r = itemBoundingBoxRect(tx, ty, listIndex);
+ r.move(itemOffsetForAlignment(textRun, itemStyle, itemFont, r));
+
if (isOptionGroupElement(element)) {
FontDescription d = itemFont.fontDescription();
d.setWeight(d.bolderWeight());
@@ -357,10 +387,6 @@ void RenderListBox::paintItemForeground(PaintInfo& paintInfo, int tx, int ty, in
itemFont.update(document()->styleSelector()->fontSelector());
}
- unsigned length = itemText.length();
- const UChar* string = itemText.characters();
- TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, !itemStyle->isLeftToRightDirection(), itemStyle->unicodeBidi() == Override);
-
// Draw the item text
if (itemStyle->visibility() != HIDDEN)
paintInfo.context->drawBidiText(itemFont, textRun, r.location());
@@ -747,6 +773,14 @@ IntPoint RenderListBox::currentMousePosition() const
return view->frameView()->currentMousePosition();
}
+bool RenderListBox::shouldSuspendScrollAnimations() const
+{
+ RenderView* view = this->view();
+ if (!view)
+ return true;
+ return view->frameView()->shouldSuspendScrollAnimations();
+}
+
PassRefPtr<Scrollbar> RenderListBox::createScrollbar()
{
RefPtr<Scrollbar> widget;
diff --git a/Source/WebCore/rendering/RenderListBox.h b/Source/WebCore/rendering/RenderListBox.h
index faeede1..0e2cfd6 100644
--- a/Source/WebCore/rendering/RenderListBox.h
+++ b/Source/WebCore/rendering/RenderListBox.h
@@ -112,6 +112,9 @@ private:
virtual int visibleHeight() const;
virtual int visibleWidth() const;
virtual IntPoint currentMousePosition() const;
+ virtual bool shouldSuspendScrollAnimations() const;
+
+ virtual void disconnectFromPage() { m_page = 0; }
// NOTE: This should only be called by the overriden setScrollOffset from ScrollableArea.
void scrollTo(int newOffset);
@@ -138,6 +141,8 @@ private:
int m_indexOffset;
RefPtr<Scrollbar> m_vBar;
+
+ Page* m_page;
};
inline RenderListBox* toRenderListBox(RenderObject* object)
diff --git a/Source/WebCore/rendering/RenderMedia.cpp b/Source/WebCore/rendering/RenderMedia.cpp
index bbb5880..69d71ec 100644
--- a/Source/WebCore/rendering/RenderMedia.cpp
+++ b/Source/WebCore/rendering/RenderMedia.cpp
@@ -89,8 +89,6 @@ void RenderMedia::layout()
// and this method will be called many times per second during playback, use a LayoutStateMaintainer:
LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
- m_controls->updateTimeDisplayVisibility();
-
controlsRenderer->setLocation(borderLeft() + paddingLeft(), borderTop() + paddingTop());
controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed));
controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed));
diff --git a/Source/WebCore/rendering/RenderMenuList.cpp b/Source/WebCore/rendering/RenderMenuList.cpp
index 8c11959..f155614 100644
--- a/Source/WebCore/rendering/RenderMenuList.cpp
+++ b/Source/WebCore/rendering/RenderMenuList.cpp
@@ -110,6 +110,7 @@ void RenderMenuList::addChild(RenderObject* newChild, RenderObject* beforeChild)
{
createInnerBlock();
m_innerBlock->addChild(newChild, beforeChild);
+ ASSERT(m_innerBlock == firstChild());
}
void RenderMenuList::removeChild(RenderObject* oldChild)
diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp
index d06db14..7cc6f1f 100644
--- a/Source/WebCore/rendering/RenderObject.cpp
+++ b/Source/WebCore/rendering/RenderObject.cpp
@@ -194,6 +194,7 @@ RenderObject::RenderObject(Node* node)
, m_needsPositionedMovementLayout(false)
, m_normalChildNeedsLayout(false)
, m_posChildNeedsLayout(false)
+ , m_needsSimplifiedNormalFlowLayout(false)
, m_preferredLogicalWidthsDirty(false)
, m_floating(false)
, m_positioned(false)
@@ -204,6 +205,7 @@ RenderObject::RenderObject(Node* node)
, m_isBox(false)
, m_inline(true)
, m_replaced(false)
+ , m_horizontalWritingMode(true)
, m_isDragging(false)
, m_hasLayer(false)
, m_hasOverflowClip(false)
@@ -218,7 +220,6 @@ RenderObject::RenderObject(Node* node)
, m_hasMarkupTruncation(false)
, m_selectionState(SelectionNone)
, m_hasColumns(false)
- , m_cellWidthChanged(false)
{
#ifndef NDEBUG
renderObjectCounter.increment();
@@ -904,7 +905,7 @@ IntRect RenderObject::borderInnerRect(const IntRect& borderRect, unsigned short
}
#if HAVE(PATH_BASED_BORDER_RADIUS_DRAWING)
-void RenderObject::drawBoxSideFromPath(GraphicsContext* graphicsContext, IntRect borderRect, Path borderPath,
+void RenderObject::drawBoxSideFromPath(GraphicsContext* graphicsContext, const IntRect& borderRect, const Path& borderPath,
float thickness, float drawThickness, BoxSide s, const RenderStyle* style,
Color c, EBorderStyle borderStyle)
{
@@ -1051,7 +1052,7 @@ void RenderObject::drawBoxSideFromPath(GraphicsContext* graphicsContext, IntRect
graphicsContext->drawRect(borderRect);
}
#else
-void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, int y, float thickness, IntSize radius,
+void RenderObject::drawArcForBoxSide(GraphicsContext* graphicsContext, int x, int y, float thickness, const IntSize& radius,
int angleStart, int angleSpan, BoxSide s, Color c,
EBorderStyle style, bool firstCorner)
{
@@ -1689,9 +1690,12 @@ StyleDifference RenderObject::adjustStyleDifference(StyleDifference diff, unsign
// Text nodes share style with their parents but transforms don't apply to them,
// hence the !isText() check.
// FIXME: when transforms are taken into account for overflow, we will need to do a layout.
- if (!isText() && (!hasLayer() || !toRenderBoxModelObject(this)->layer()->isComposited()))
- diff = StyleDifferenceLayout;
- else if (diff < StyleDifferenceRecompositeLayer)
+ if (!isText() && (!hasLayer() || !toRenderBoxModelObject(this)->layer()->isComposited())) {
+ if (!hasLayer())
+ diff = StyleDifferenceLayout; // FIXME: Do this for now since SimplifiedLayout cannot handle updating floating objects lists.
+ else if (diff < StyleDifferenceSimplifiedLayout)
+ diff = StyleDifferenceSimplifiedLayout;
+ } else if (diff < StyleDifferenceRecompositeLayer)
diff = StyleDifferenceRecompositeLayer;
}
@@ -1770,6 +1774,8 @@ void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
setNeedsLayoutAndPrefWidthsRecalc();
else if (updatedDiff == StyleDifferenceLayoutPositionedMovementOnly)
setNeedsPositionedMovementLayout();
+ else if (updatedDiff == StyleDifferenceSimplifiedLayout)
+ setNeedsSimplifiedNormalFlowLayout();
}
if (updatedDiff == StyleDifferenceRepaintLayer || updatedDiff == StyleDifferenceRepaint) {
@@ -1835,6 +1841,7 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
m_positioned = false;
m_relPositioned = false;
}
+ m_horizontalWritingMode = true;
m_paintBackground = false;
m_hasOverflowClip = false;
m_hasTransform = false;
@@ -1882,7 +1889,7 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
if (!m_parent)
return;
- if (diff == StyleDifferenceLayout) {
+ if (diff == StyleDifferenceLayout || diff == StyleDifferenceSimplifiedLayout) {
RenderCounter::rendererStyleChanged(this, oldStyle, m_style.get());
// If the object already needs layout, then setNeedsLayout won't do
@@ -1893,7 +1900,10 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
if (m_needsLayout && oldStyle->position() != m_style->position())
markContainingBlocksForLayout();
- setNeedsLayoutAndPrefWidthsRecalc();
+ if (diff == StyleDifferenceLayout)
+ setNeedsLayoutAndPrefWidthsRecalc();
+ else
+ setNeedsSimplifiedNormalFlowLayout();
} else if (diff == StyleDifferenceLayoutPositionedMovementOnly)
setNeedsPositionedMovementLayout();
@@ -1939,7 +1949,7 @@ IntRect RenderObject::viewRect() const
return view()->viewRect();
}
-FloatPoint RenderObject::localToAbsolute(FloatPoint localPoint, bool fixed, bool useTransforms) const
+FloatPoint RenderObject::localToAbsolute(const FloatPoint& localPoint, bool fixed, bool useTransforms) const
{
TransformState transformState(TransformState::ApplyTransformDirection, localPoint);
mapLocalToContainer(0, fixed, useTransforms, transformState);
@@ -1948,7 +1958,7 @@ FloatPoint RenderObject::localToAbsolute(FloatPoint localPoint, bool fixed, bool
return transformState.lastPlanarPoint();
}
-FloatPoint RenderObject::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const
+FloatPoint RenderObject::absoluteToLocal(const FloatPoint& containerPoint, bool fixed, bool useTransforms) const
{
TransformState transformState(TransformState::UnapplyInverseTransformDirection, containerPoint);
mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
@@ -2613,11 +2623,11 @@ RenderBoxModelObject* RenderObject::offsetParent() const
// * The computed value of the position property of A is static and the ancestor
// is one of the following HTML elements: td, th, or table.
// * Our own extension: if there is a difference in the effective zoom
+
bool skipTables = isPositioned() || isRelPositioned();
float currZoom = style()->effectiveZoom();
RenderObject* curr = parent();
- while (curr && (!curr->node() ||
- (!curr->isPositioned() && !curr->isRelPositioned() && !curr->isBody()))) {
+ while (curr && (!curr->node() || (!curr->isPositioned() && !curr->isRelPositioned() && !curr->isBody()))) {
Node* element = curr->node();
if (!skipTables && element) {
bool isTableElement = element->hasTagName(tableTag) ||
@@ -2647,14 +2657,14 @@ VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affini
{
// If this is a non-anonymous renderer in an editable area, then it's simple.
if (Node* node = this->node()) {
- if (!node->isContentEditable()) {
+ if (!node->rendererIsEditable()) {
// If it can be found, we prefer a visually equivalent position that is editable.
Position position(node, offset);
Position candidate = position.downstream(CanCrossEditingBoundary);
- if (candidate.deprecatedNode()->isContentEditable())
+ if (candidate.deprecatedNode()->rendererIsEditable())
return VisiblePosition(candidate, affinity);
candidate = position.upstream(CanCrossEditingBoundary);
- if (candidate.deprecatedNode()->isContentEditable())
+ if (candidate.deprecatedNode()->rendererIsEditable())
return VisiblePosition(candidate, affinity);
}
// FIXME: Eliminate legacy editing positions
diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h
index 8b9fa38..41564dd 100644
--- a/Source/WebCore/rendering/RenderObject.h
+++ b/Source/WebCore/rendering/RenderObject.h
@@ -320,8 +320,6 @@ public:
void setChildrenInline(bool b = true) { m_childrenInline = b; }
bool hasColumns() const { return m_hasColumns; }
void setHasColumns(bool b = true) { m_hasColumns = b; }
- bool cellWidthChanged() const { return m_cellWidthChanged; }
- void setCellWidthChanged(bool b = true) { m_cellWidthChanged = b; }
virtual bool requiresForcedStyleRecalcPropagation() const { return false; }
@@ -388,7 +386,11 @@ public:
void setIsAnonymous(bool b) { m_isAnonymous = b; }
bool isAnonymousBlock() const
{
- return m_isAnonymous && style()->display() == BLOCK && style()->styleType() == NOPSEUDO && !isListMarker();
+ // This function is kept in sync with anonymous block creation conditions in
+ // RenderBlock::createAnonymousBlock(). This includes creating an anonymous
+ // RenderBlock having a BLOCK or BOX display. Other classes such as RenderTextFragment
+ // are not RenderBlocks and will return false. See https://bugs.webkit.org/show_bug.cgi?id=56709.
+ return m_isAnonymous && (style()->display() == BLOCK || style()->display() == BOX) && style()->styleType() == NOPSEUDO && isRenderBlock() && !isListMarker();
}
bool isAnonymousColumnsBlock() const { return style()->specifiesColumns() && isAnonymousBlock(); }
bool isAnonymousColumnSpanBlock() const { return style()->columnSpan() && isAnonymousBlock(); }
@@ -406,17 +408,19 @@ public:
bool isRunIn() const { return style()->display() == RUN_IN; } // run-in object
bool isDragging() const { return m_isDragging; }
bool isReplaced() const { return m_replaced; } // a "replaced" element (see CSS)
-
+ bool isHorizontalWritingMode() const { return m_horizontalWritingMode; }
+
bool hasLayer() const { return m_hasLayer; }
bool hasBoxDecorations() const { return m_paintBackground; }
bool mustRepaintBackgroundOrBorder() const;
bool hasBackground() const { return style()->hasBackground(); }
- bool needsLayout() const { return m_needsLayout || m_normalChildNeedsLayout || m_posChildNeedsLayout || m_needsPositionedMovementLayout; }
+ bool needsLayout() const { return m_needsLayout || m_normalChildNeedsLayout || m_posChildNeedsLayout || m_needsSimplifiedNormalFlowLayout || m_needsPositionedMovementLayout; }
bool selfNeedsLayout() const { return m_needsLayout; }
bool needsPositionedMovementLayout() const { return m_needsPositionedMovementLayout; }
- bool needsPositionedMovementLayoutOnly() const { return m_needsPositionedMovementLayout && !m_needsLayout && !m_normalChildNeedsLayout && !m_posChildNeedsLayout; }
+ bool needsPositionedMovementLayoutOnly() const { return m_needsPositionedMovementLayout && !m_needsLayout && !m_normalChildNeedsLayout && !m_posChildNeedsLayout && !m_needsSimplifiedNormalFlowLayout; }
bool posChildNeedsLayout() const { return m_posChildNeedsLayout; }
+ bool needsSimplifiedNormalFlowLayout() const { return m_needsSimplifiedNormalFlowLayout; }
bool normalChildNeedsLayout() const { return m_normalChildNeedsLayout; }
bool preferredLogicalWidthsDirty() const { return m_preferredLogicalWidthsDirty; }
@@ -432,13 +436,13 @@ public:
void drawLineForBoxSide(GraphicsContext*, int x1, int y1, int x2, int y2, BoxSide,
Color, EBorderStyle, int adjbw1, int adjbw2);
#if HAVE(PATH_BASED_BORDER_RADIUS_DRAWING)
- void drawBoxSideFromPath(GraphicsContext*, IntRect, Path,
+ void drawBoxSideFromPath(GraphicsContext*, const IntRect&, const Path&,
float thickness, float drawThickness, BoxSide, const RenderStyle*,
Color, EBorderStyle);
#else
// FIXME: This function should be removed when all ports implement GraphicsContext::clipConvexPolygon()!!
// At that time, everyone can use RenderObject::drawBoxSideFromPath() instead. This should happen soon.
- void drawArcForBoxSide(GraphicsContext*, int x, int y, float thickness, IntSize radius, int angleStart,
+ void drawArcForBoxSide(GraphicsContext*, int x, int y, float thickness, const IntSize& radius, int angleStart,
int angleSpan, BoxSide, Color, EBorderStyle, bool firstCorner);
#endif
@@ -485,6 +489,7 @@ public:
void setNeedsLayout(bool b, bool markParents = true);
void setChildNeedsLayout(bool b, bool markParents = true);
void setNeedsPositionedMovementLayout();
+ void setNeedsSimplifiedNormalFlowLayout();
void setPreferredLogicalWidthsDirty(bool, bool markParents = true);
void invalidateContainerPreferredLogicalWidths();
@@ -502,6 +507,7 @@ public:
void setIsText() { m_isText = true; }
void setIsBox() { m_isBox = true; }
void setReplaced(bool b = true) { m_replaced = b; }
+ void setHorizontalWritingMode(bool b = true) { m_horizontalWritingMode = b; }
void setHasOverflowClip(bool b = true) { m_hasOverflowClip = b; }
void setHasLayer(bool b = true) { m_hasLayer = b; }
void setHasTransform(bool b = true) { m_hasTransform = b; }
@@ -557,8 +563,8 @@ public:
// Convert the given local point to absolute coordinates
// FIXME: Temporary. If useTransforms is true, take transforms into account. Eventually localToAbsolute() will always be transform-aware.
- FloatPoint localToAbsolute(FloatPoint localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const;
- FloatPoint absoluteToLocal(FloatPoint, bool fixed = false, bool useTransforms = false) const;
+ FloatPoint localToAbsolute(const FloatPoint& localPoint = FloatPoint(), bool fixed = false, bool useTransforms = false) const;
+ FloatPoint absoluteToLocal(const FloatPoint&, bool fixed = false, bool useTransforms = false) const;
// Convert a local quad to absolute coordinates, taking transforms into account.
FloatQuad localToAbsoluteQuad(const FloatQuad& quad, bool fixed = false) const
@@ -730,6 +736,8 @@ public:
virtual bool isFlexingChildren() const { return false; }
virtual bool isStretchingChildren() const { return false; }
+ virtual bool isCombineText() const { return false; }
+
virtual int caretMinOffset() const;
virtual int caretMaxOffset() const;
virtual unsigned caretMaxRenderedOffset() const;
@@ -840,6 +848,7 @@ private:
bool m_needsPositionedMovementLayout :1;
bool m_normalChildNeedsLayout : 1;
bool m_posChildNeedsLayout : 1;
+ bool m_needsSimplifiedNormalFlowLayout : 1;
bool m_preferredLogicalWidthsDirty : 1;
bool m_floating : 1;
@@ -853,6 +862,7 @@ private:
bool m_isBox : 1;
bool m_inline : 1;
bool m_replaced : 1;
+ bool m_horizontalWritingMode : 1;
bool m_isDragging : 1;
bool m_hasLayer : 1;
@@ -924,6 +934,7 @@ inline void RenderObject::setNeedsLayout(bool b, bool markParents)
} else {
m_everHadLayout = true;
m_posChildNeedsLayout = false;
+ m_needsSimplifiedNormalFlowLayout = false;
m_normalChildNeedsLayout = false;
m_needsPositionedMovementLayout = false;
}
@@ -939,6 +950,7 @@ inline void RenderObject::setChildNeedsLayout(bool b, bool markParents)
markContainingBlocksForLayout();
} else {
m_posChildNeedsLayout = false;
+ m_needsSimplifiedNormalFlowLayout = false;
m_normalChildNeedsLayout = false;
m_needsPositionedMovementLayout = false;
}
@@ -955,6 +967,17 @@ inline void RenderObject::setNeedsPositionedMovementLayout()
}
}
+inline void RenderObject::setNeedsSimplifiedNormalFlowLayout()
+{
+ bool alreadyNeededLayout = needsLayout();
+ m_needsSimplifiedNormalFlowLayout = true;
+ if (!alreadyNeededLayout) {
+ markContainingBlocksForLayout();
+ if (hasLayer())
+ setLayerNeedsFullRepaint();
+ }
+}
+
inline bool objectIsRelayoutBoundary(const RenderObject *obj)
{
// FIXME: In future it may be possible to broaden this condition in order to improve performance.
@@ -975,6 +998,8 @@ inline void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, R
RenderObject* o = container();
RenderObject* last = this;
+ bool simplifiedNormalFlowLayout = needsSimplifiedNormalFlowLayout() && !selfNeedsLayout() && !normalChildNeedsLayout();
+
while (o) {
// Don't mark the outermost object of an unrooted subtree. That object will be
// marked when the subtree is added to the document.
@@ -982,17 +1007,15 @@ inline void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, R
if (!container && !o->isRenderView())
return;
if (!last->isText() && (last->style()->position() == FixedPosition || last->style()->position() == AbsolutePosition)) {
- if (last->style()->top().isAuto() && last->style()->bottom().isAuto()) {
- RenderObject* parent = last->parent();
- if (!parent->normalChildNeedsLayout()) {
- parent->setChildNeedsLayout(true, false);
- if (parent != newRoot)
- parent->markContainingBlocksForLayout(scheduleRelayout, newRoot);
- }
- }
if (o->m_posChildNeedsLayout)
return;
o->m_posChildNeedsLayout = true;
+ simplifiedNormalFlowLayout = true;
+ ASSERT(!o->isSetNeedsLayoutForbidden());
+ } else if (simplifiedNormalFlowLayout) {
+ if (o->m_needsSimplifiedNormalFlowLayout)
+ return;
+ o->m_needsSimplifiedNormalFlowLayout = true;
ASSERT(!o->isSetNeedsLayoutForbidden());
} else {
if (o->m_normalChildNeedsLayout)
diff --git a/Source/WebCore/rendering/RenderObjectChildList.cpp b/Source/WebCore/rendering/RenderObjectChildList.cpp
index 4df7180..617067a 100644
--- a/Source/WebCore/rendering/RenderObjectChildList.cpp
+++ b/Source/WebCore/rendering/RenderObjectChildList.cpp
@@ -262,31 +262,6 @@ static RenderObject* findBeforeAfterParent(RenderObject* object)
return beforeAfterParent;
}
-static void invalidateCountersInContainer(RenderObject* container, const AtomicString& identifier)
-{
- if (!container)
- return;
- container = findBeforeAfterParent(container);
- if (!container)
- return;
- // Sometimes the counter is attached directly on the container.
- if (container->isCounter()) {
- toRenderCounter(container)->invalidate(identifier);
- return;
- }
- for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) {
- if (content->isCounter())
- toRenderCounter(content)->invalidate(identifier);
- }
-}
-
-void RenderObjectChildList::invalidateCounters(const RenderObject* owner, const AtomicString& identifier)
-{
- ASSERT(!owner->documentBeingDestroyed());
- invalidateCountersInContainer(beforePseudoElementRenderer(owner), identifier);
- invalidateCountersInContainer(afterPseudoElementRenderer(owner), identifier);
-}
-
RenderObject* RenderObjectChildList::beforePseudoElementRenderer(const RenderObject* owner) const
{
// An anonymous (generated) inline run-in that has PseudoId BEFORE must come from a grandparent.
diff --git a/Source/WebCore/rendering/RenderObjectChildList.h b/Source/WebCore/rendering/RenderObjectChildList.h
index 087adfb..c8fc978 100644
--- a/Source/WebCore/rendering/RenderObjectChildList.h
+++ b/Source/WebCore/rendering/RenderObjectChildList.h
@@ -58,7 +58,6 @@ public:
void updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject = 0);
RenderObject* beforePseudoElementRenderer(const RenderObject* owner) const;
RenderObject* afterPseudoElementRenderer(const RenderObject* owner) const;
- void invalidateCounters(const RenderObject* owner, const AtomicString& identifier);
private:
RenderObject* m_firstChild;
diff --git a/Source/WebCore/rendering/RenderRubyRun.cpp b/Source/WebCore/rendering/RenderRubyRun.cpp
index 016c2a1..3504ccf 100644
--- a/Source/WebCore/rendering/RenderRubyRun.cpp
+++ b/Source/WebCore/rendering/RenderRubyRun.cpp
@@ -194,8 +194,7 @@ void RenderRubyRun::removeChild(RenderObject* child)
RenderRubyBase* RenderRubyRun::createRubyBase() const
{
RenderRubyBase* rb = new (renderArena()) RenderRubyBase(document() /* anonymous */);
- RefPtr<RenderStyle> newStyle = RenderStyle::create();
- newStyle->inheritFrom(style());
+ RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
newStyle->setDisplay(BLOCK);
newStyle->setTextAlign(CENTER); // FIXME: use WEBKIT_CENTER?
rb->setStyle(newStyle.release());
@@ -206,8 +205,7 @@ RenderRubyRun* RenderRubyRun::staticCreateRubyRun(const RenderObject* parentRuby
{
ASSERT(parentRuby && parentRuby->isRuby());
RenderRubyRun* rr = new (parentRuby->renderArena()) RenderRubyRun(parentRuby->document() /* anonymous */);
- RefPtr<RenderStyle> newStyle = RenderStyle::create();
- newStyle->inheritFrom(parentRuby->style());
+ RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(parentRuby->style());
newStyle->setDisplay(INLINE_BLOCK);
rr->setStyle(newStyle.release());
return rr;
diff --git a/Source/WebCore/rendering/RenderSlider.cpp b/Source/WebCore/rendering/RenderSlider.cpp
index 49da396..1661b7a 100644
--- a/Source/WebCore/rendering/RenderSlider.cpp
+++ b/Source/WebCore/rendering/RenderSlider.cpp
@@ -156,7 +156,7 @@ void RenderSlider::layout()
if (oldSize != size())
thumb->setChildNeedsLayout(true, false);
- LayoutStateMaintainer statePusher(view(), this, size(), style()->isFlippedBlocksWritingMode());
+ LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), style()->isFlippedBlocksWritingMode());
IntRect oldThumbRect = thumb->frameRect();
diff --git a/Source/WebCore/rendering/RenderSummary.cpp b/Source/WebCore/rendering/RenderSummary.cpp
index 8fccf66..cfde231 100644
--- a/Source/WebCore/rendering/RenderSummary.cpp
+++ b/Source/WebCore/rendering/RenderSummary.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,11 +21,41 @@
#include "config.h"
#include "RenderSummary.h"
+#include "RenderDetails.h"
+
namespace WebCore {
-RenderSummary::RenderSummary(Node* element)
- : RenderBlock(element)
+RenderSummary::RenderSummary(Node* node)
+ : RenderBlock(node)
+{
+}
+
+void RenderSummary::destroy()
+{
+ RenderDetails* details = parentDetails();
+ if (details)
+ details->summaryDestroyed(this);
+
+ RenderBlock::destroy();
+}
+
+RenderDetails* RenderSummary::parentDetails()
{
+ RenderObject* obj = parent();
+ while (obj && !obj->isDetails())
+ obj = obj->parent();
+
+ return static_cast<RenderDetails*>(obj);
+}
+
+void RenderSummary::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderBlock::styleDidChange(diff, oldStyle);
+
+
+ // Ensure that if we ended up being inline that we set our replaced flag
+ // so that we're treated like an inline-block.
+ setReplaced(isInline());
}
}
diff --git a/Source/WebCore/rendering/RenderSummary.h b/Source/WebCore/rendering/RenderSummary.h
index afc18fa..94850df 100644
--- a/Source/WebCore/rendering/RenderSummary.h
+++ b/Source/WebCore/rendering/RenderSummary.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -25,13 +25,20 @@
namespace WebCore {
+class RenderDetails;
+
class RenderSummary : public RenderBlock {
public:
explicit RenderSummary(Node*);
+ virtual void destroy();
+
private:
virtual const char* renderName() const { return "RenderSummary"; }
virtual bool isSummary() const { return true; }
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+
+ RenderDetails* parentDetails();
};
inline RenderSummary* toRenderSummary(RenderObject* object)
diff --git a/Source/WebCore/rendering/RenderTable.cpp b/Source/WebCore/rendering/RenderTable.cpp
index 69c073c..187ffd7 100644
--- a/Source/WebCore/rendering/RenderTable.cpp
+++ b/Source/WebCore/rendering/RenderTable.cpp
@@ -277,7 +277,7 @@ void RenderTable::layout()
{
ASSERT(needsLayout());
- if (layoutOnlyPositionedObjects())
+ if (simplifiedLayout())
return;
recalcSectionsIfNeeded();
@@ -510,11 +510,14 @@ void RenderTable::paint(PaintInfo& paintInfo, int tx, int ty)
PaintPhase paintPhase = paintInfo.phase;
- int os = 2 * maximalOutlineSize(paintPhase);
- if (ty + minYVisualOverflow() >= paintInfo.rect.maxY() + os || ty + maxYVisualOverflow() <= paintInfo.rect.y() - os)
- return;
- if (tx + minXVisualOverflow() >= paintInfo.rect.maxX() + os || tx + maxXVisualOverflow() <= paintInfo.rect.x() - os)
- return;
+ if (!isRoot()) {
+ IntRect overflowBox = visualOverflowRect();
+ flipForWritingMode(overflowBox);
+ overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
+ overflowBox.move(tx, ty);
+ if (!overflowBox.intersects(paintInfo.rect))
+ return;
+ }
bool pushedClip = pushContentsClip(paintInfo, tx, ty);
paintObject(paintInfo, tx, ty);
@@ -609,7 +612,13 @@ void RenderTable::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
paintBoxShadow(paintInfo.context, rect.x(), rect.y(), rect.width(), rect.height(), style(), Normal);
- paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), rect.x(), rect.y(), rect.width(), rect.height());
+ if (isRoot())
+ paintRootBoxFillLayers(paintInfo);
+ else if (!isBody() || document()->documentElement()->renderer()->hasBackground())
+ // The <body> only paints its background if the root element has defined a background
+ // independent of the body.
+ paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), rect.x(), rect.y(), rect.width(), rect.height());
+
paintBoxShadow(paintInfo.context, rect.x(), rect.y(), rect.width(), rect.height(), style(), Inset);
if (style()->hasBorder() && !collapseBorders())
@@ -1199,9 +1208,9 @@ int RenderTable::firstLineBoxBaseline() const
return firstNonEmptySection->logicalTop() + firstNonEmptySection->firstLineBoxBaseline();
}
-IntRect RenderTable::overflowClipRect(int tx, int ty)
+IntRect RenderTable::overflowClipRect(int tx, int ty, OverlayScrollbarSizeRelevancy relevancy)
{
- IntRect rect = RenderBlock::overflowClipRect(tx, ty);
+ IntRect rect = RenderBlock::overflowClipRect(tx, ty, relevancy);
// If we have a caption, expand the clip to include the caption.
// FIXME: Technically this is wrong, but it's virtually impossible to fix this
diff --git a/Source/WebCore/rendering/RenderTable.h b/Source/WebCore/rendering/RenderTable.h
index 67a311c..d781e95 100644
--- a/Source/WebCore/rendering/RenderTable.h
+++ b/Source/WebCore/rendering/RenderTable.h
@@ -236,7 +236,7 @@ private:
virtual void computeLogicalWidth();
- virtual IntRect overflowClipRect(int tx, int ty);
+ virtual IntRect overflowClipRect(int tx, int ty, OverlayScrollbarSizeRelevancy relevancy = IgnoreOverlayScrollbarSize);
virtual void addOverflowFromChildren();
diff --git a/Source/WebCore/rendering/RenderTableCell.cpp b/Source/WebCore/rendering/RenderTableCell.cpp
index 2293bac..c9d8837 100644
--- a/Source/WebCore/rendering/RenderTableCell.cpp
+++ b/Source/WebCore/rendering/RenderTableCell.cpp
@@ -52,6 +52,7 @@ RenderTableCell::RenderTableCell(Node* node)
, m_column(-1)
, m_rowSpan(1)
, m_columnSpan(1)
+ , m_cellWidthChanged(false)
, m_intrinsicPaddingBefore(0)
, m_intrinsicPaddingAfter(0)
{
@@ -174,7 +175,7 @@ void RenderTableCell::layout()
int RenderTableCell::paddingTop(bool includeIntrinsicPadding) const
{
int result = RenderBlock::paddingTop();
- if (!includeIntrinsicPadding || !style()->isHorizontalWritingMode())
+ if (!includeIntrinsicPadding || !isHorizontalWritingMode())
return result;
return result + (style()->writingMode() == TopToBottomWritingMode ? intrinsicPaddingBefore() : intrinsicPaddingAfter());
}
@@ -182,7 +183,7 @@ int RenderTableCell::paddingTop(bool includeIntrinsicPadding) const
int RenderTableCell::paddingBottom(bool includeIntrinsicPadding) const
{
int result = RenderBlock::paddingBottom();
- if (!includeIntrinsicPadding || !style()->isHorizontalWritingMode())
+ if (!includeIntrinsicPadding || !isHorizontalWritingMode())
return result;
return result + (style()->writingMode() == TopToBottomWritingMode ? intrinsicPaddingAfter() : intrinsicPaddingBefore());
}
@@ -190,7 +191,7 @@ int RenderTableCell::paddingBottom(bool includeIntrinsicPadding) const
int RenderTableCell::paddingLeft(bool includeIntrinsicPadding) const
{
int result = RenderBlock::paddingLeft();
- if (!includeIntrinsicPadding || style()->isHorizontalWritingMode())
+ if (!includeIntrinsicPadding || isHorizontalWritingMode())
return result;
return result + (style()->writingMode() == LeftToRightWritingMode ? intrinsicPaddingBefore() : intrinsicPaddingAfter());
@@ -199,7 +200,7 @@ int RenderTableCell::paddingLeft(bool includeIntrinsicPadding) const
int RenderTableCell::paddingRight(bool includeIntrinsicPadding) const
{
int result = RenderBlock::paddingRight();
- if (!includeIntrinsicPadding || style()->isHorizontalWritingMode())
+ if (!includeIntrinsicPadding || isHorizontalWritingMode())
return result;
return result + (style()->writingMode() == LeftToRightWritingMode ? intrinsicPaddingAfter() : intrinsicPaddingBefore());
}
@@ -225,6 +226,12 @@ void RenderTableCell::setOverrideSize(int size)
clearIntrinsicPadding();
RenderBlock::setOverrideSize(size);
}
+
+void RenderTableCell::setOverrideSizeFromRowHeight(int rowHeight)
+{
+ clearIntrinsicPadding();
+ RenderBlock::setOverrideSize(max(0, rowHeight - borderBefore() - paddingBefore() - borderAfter() - paddingAfter()));
+}
IntSize RenderTableCell::offsetFromContainer(RenderObject* o, const IntPoint& point) const
{
@@ -1049,8 +1056,8 @@ void RenderTableCell::scrollbarsChanged(bool horizontalScrollbarChanged, bool ve
return; // Not sure if we should be doing something when a scrollbar goes away or not.
// We only care if the scrollbar that affects our intrinsic padding has been added.
- if ((style()->isHorizontalWritingMode() && !horizontalScrollbarChanged) ||
- (!style()->isHorizontalWritingMode() && !verticalScrollbarChanged))
+ if ((isHorizontalWritingMode() && !horizontalScrollbarChanged) ||
+ (!isHorizontalWritingMode() && !verticalScrollbarChanged))
return;
// Shrink our intrinsic padding as much as possible to accommodate the scrollbar.
diff --git a/Source/WebCore/rendering/RenderTableCell.h b/Source/WebCore/rendering/RenderTableCell.h
index cfdb739..9884999 100644
--- a/Source/WebCore/rendering/RenderTableCell.h
+++ b/Source/WebCore/rendering/RenderTableCell.h
@@ -120,11 +120,15 @@ public:
virtual int paddingAfter(bool includeIntrinsicPadding = true) const;
virtual void setOverrideSize(int);
+ void setOverrideSizeFromRowHeight(int);
bool hasVisualOverflow() const { return m_overflow && !borderBoxRect().contains(m_overflow->visualOverflowRect()); }
virtual void scrollbarsChanged(bool horizontalScrollbarChanged, bool verticalScrollbarChanged);
+ bool cellWidthChanged() const { return m_cellWidthChanged; }
+ void setCellWidthChanged(bool b = true) { m_cellWidthChanged = b; }
+
protected:
virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
@@ -136,8 +140,6 @@ private:
virtual void destroy();
- virtual bool requiresLayer() const { return isPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection(); }
-
virtual void computeLogicalWidth();
virtual void paintBoxDecorations(PaintInfo&, int tx, int ty);
@@ -152,7 +154,8 @@ private:
int m_row;
int m_column;
int m_rowSpan;
- int m_columnSpan;
+ int m_columnSpan : 31;
+ bool m_cellWidthChanged : 1;
int m_intrinsicPaddingBefore;
int m_intrinsicPaddingAfter;
};
diff --git a/Source/WebCore/rendering/RenderTableRow.cpp b/Source/WebCore/rendering/RenderTableRow.cpp
index 7300c19..a29f218 100644
--- a/Source/WebCore/rendering/RenderTableRow.cpp
+++ b/Source/WebCore/rendering/RenderTableRow.cpp
@@ -63,6 +63,17 @@ void RenderTableRow::styleWillChange(StyleDifference diff, const RenderStyle* ne
RenderBox::styleWillChange(diff, newStyle);
}
+void RenderTableRow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
+{
+ RenderBox::styleDidChange(diff, oldStyle);
+
+ // Update pseudos for :before and :after now.
+ if (!isAnonymous() && document()->usesBeforeAfterRules()) {
+ children()->updateBeforeAfterContent(this, BEFORE);
+ children()->updateBeforeAfterContent(this, AFTER);
+ }
+}
+
void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild)
{
// Make sure we don't append things after :after-generated content if we have it.
diff --git a/Source/WebCore/rendering/RenderTableRow.h b/Source/WebCore/rendering/RenderTableRow.h
index 20aa424..2af8dcb 100644
--- a/Source/WebCore/rendering/RenderTableRow.h
+++ b/Source/WebCore/rendering/RenderTableRow.h
@@ -62,6 +62,7 @@ private:
virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle);
+ virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
RenderObjectChildList m_children;
};
diff --git a/Source/WebCore/rendering/RenderTableSection.cpp b/Source/WebCore/rendering/RenderTableSection.cpp
index 3d46ece..7c0a768 100644
--- a/Source/WebCore/rendering/RenderTableSection.cpp
+++ b/Source/WebCore/rendering/RenderTableSection.cpp
@@ -203,7 +203,7 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row)
switch (logicalHeight.type()) {
case Percent:
if (!(cRowLogicalHeight.isPercent()) ||
- (cRowLogicalHeight.isPercent() && cRowLogicalHeight.rawValue() < logicalHeight.rawValue()))
+ (cRowLogicalHeight.isPercent() && cRowLogicalHeight.percent() < logicalHeight.percent()))
m_grid[m_cRow].logicalHeight = logicalHeight;
break;
case Fixed:
@@ -521,22 +521,22 @@ int RenderTableSection::layoutRows(int toAdd)
if (m_grid[r].logicalHeight.isAuto())
numAuto++;
else if (m_grid[r].logicalHeight.isPercent())
- totalPercent += m_grid[r].logicalHeight.rawValue();
+ totalPercent += m_grid[r].logicalHeight.percent();
}
if (totalPercent) {
// try to satisfy percent
int add = 0;
- totalPercent = min(totalPercent, 100 * percentScaleFactor);
+ totalPercent = min(totalPercent, 100);
int rh = m_rowPos[1] - m_rowPos[0];
for (int r = 0; r < totalRows; r++) {
if (totalPercent > 0 && m_grid[r].logicalHeight.isPercent()) {
- int toAdd = min(dh, (totalHeight * m_grid[r].logicalHeight.rawValue() / (100 * percentScaleFactor)) - rh);
+ int toAdd = min(dh, static_cast<int>((totalHeight * m_grid[r].logicalHeight.percent() / 100) - rh));
// If toAdd is negative, then we don't want to shrink the row (this bug
// affected Outlook Web Access).
toAdd = max(0, toAdd);
add += toAdd;
dh -= toAdd;
- totalPercent -= m_grid[r].logicalHeight.rawValue();
+ totalPercent -= m_grid[r].logicalHeight.percent();
}
if (r < totalRows - 1)
rh = m_rowPos[r + 2] - m_rowPos[r + 1];
@@ -647,9 +647,7 @@ int RenderTableSection::layoutRows(int toAdd)
// Alignment within a cell is based off the calculated
// height, which becomes irrelevant once the cell has
// been resized based off its percentage.
- cell->setOverrideSize(max(0,
- rHeight - cell->borderBefore() - cell->paddingBefore() -
- cell->borderAfter() - cell->paddingAfter()));
+ cell->setOverrideSizeFromRowHeight(rHeight);
cell->layoutIfNeeded();
// If the baseline moved, we may have to update the data for our row. Find out the new baseline.
diff --git a/Source/WebCore/rendering/RenderText.cpp b/Source/WebCore/rendering/RenderText.cpp
index 3e696d3..e660875 100644
--- a/Source/WebCore/rendering/RenderText.cpp
+++ b/Source/WebCore/rendering/RenderText.cpp
@@ -551,6 +551,12 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e
case CENTER:
case WEBKIT_CENTER:
break;
+ case TASTART:
+ rightAligned = !cbStyle->isLeftToRightDirection();
+ break;
+ case TAEND:
+ rightAligned = cbStyle->isLeftToRightDirection();
+ break;
}
if (rightAligned) {
@@ -566,13 +572,13 @@ IntRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, int* e
ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
{
- if (style()->hasTextCombine()) {
+ if (style()->hasTextCombine() && isCombineText()) {
const RenderCombineText* combineText = toRenderCombineText(this);
if (combineText->isCombined())
return combineText->combinedTextWidth(f);
}
- if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII) {
+ if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) {
float monospaceCharacterWidth = f.spaceWidth();
float tabWidth = allowTabs() ? monospaceCharacterWidth * 8 : 0;
float w = 0;
@@ -1247,7 +1253,7 @@ float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos,
float w;
if (&f == &style()->font()) {
- if (!style()->preserveNewline() && !from && len == textLength()) {
+ if (!style()->preserveNewline() && !from && len == textLength() && (!glyphOverflow || !glyphOverflow->computeBounds)) {
if (fallbackFonts) {
ASSERT(glyphOverflow);
if (preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts) {
@@ -1404,6 +1410,8 @@ int RenderText::previousOffset(int current) const
return result;
}
+#if PLATFORM(MAC)
+
#define HANGUL_CHOSEONG_START (0x1100)
#define HANGUL_CHOSEONG_END (0x115F)
#define HANGUL_JUNGSEONG_START (0x1160)
@@ -1428,6 +1436,14 @@ inline bool isHangulLVT(UChar32 character)
return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT;
}
+inline bool isMark(UChar32 c)
+{
+ int8_t charType = u_charType(c);
+ return charType == U_NON_SPACING_MARK || charType == U_ENCLOSING_MARK || charType == U_COMBINING_SPACING_MARK;
+}
+
+#endif
+
int RenderText::previousOffsetForBackwardDeletion(int current) const
{
#if PLATFORM(MAC)
@@ -1446,7 +1462,7 @@ int RenderText::previousOffsetForBackwardDeletion(int current) const
if ((character >= 0x0530) && (character < 0x1950))
break;
- if (u_isbase(character) && (character != 0xFF9E) && (character != 0xFF9F))
+ if (!isMark(character) && (character != 0xFF9E) && (character != 0xFF9F))
break;
}
diff --git a/Source/WebCore/rendering/RenderText.h b/Source/WebCore/rendering/RenderText.h
index b88590c..7fa3518 100644
--- a/Source/WebCore/rendering/RenderText.h
+++ b/Source/WebCore/rendering/RenderText.h
@@ -125,6 +125,8 @@ public:
virtual void computePreferredLogicalWidths(float leadWidth);
bool isAllCollapsibleWhitespace();
+ bool knownToHaveNoOverflowAndNoFallbackFonts() const { return m_knownToHaveNoOverflowAndNoFallbackFonts; }
+
protected:
virtual void styleWillChange(StyleDifference, const RenderStyle*) { }
virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
diff --git a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp
index 8b98335..b9697ff 100644
--- a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp
+++ b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp
@@ -1111,7 +1111,7 @@ PassRefPtr<Scrollbar> RenderTextControlSingleLine::createScrollbar(ScrollableAre
InputElement* RenderTextControlSingleLine::inputElement() const
{
- return toInputElement(static_cast<Element*>(node()));
+ return node()->toInputElement();
}
int RenderTextControlSingleLine::textBlockInsetLeft() const
diff --git a/Source/WebCore/rendering/RenderTheme.cpp b/Source/WebCore/rendering/RenderTheme.cpp
index b68429c..f254c99 100644
--- a/Source/WebCore/rendering/RenderTheme.cpp
+++ b/Source/WebCore/rendering/RenderTheme.cpp
@@ -779,10 +779,10 @@ bool RenderTheme::isActive(const RenderObject* o) const
bool RenderTheme::isChecked(const RenderObject* o) const
{
- if (!o->node() || !o->node()->isElementNode())
+ if (!o->node())
return false;
- InputElement* inputElement = toInputElement(static_cast<Element*>(o->node()));
+ InputElement* inputElement = o->node()->toInputElement();
if (!inputElement)
return false;
@@ -791,10 +791,10 @@ bool RenderTheme::isChecked(const RenderObject* o) const
bool RenderTheme::isIndeterminate(const RenderObject* o) const
{
- if (!o->node() || !o->node()->isElementNode())
+ if (!o->node())
return false;
- InputElement* inputElement = toInputElement(static_cast<Element*>(o->node()));
+ InputElement* inputElement = o->node()->toInputElement();
if (!inputElement)
return false;
diff --git a/Source/WebCore/rendering/RenderTheme.h b/Source/WebCore/rendering/RenderTheme.h
index 5021712..53c23e3 100644
--- a/Source/WebCore/rendering/RenderTheme.h
+++ b/Source/WebCore/rendering/RenderTheme.h
@@ -88,6 +88,9 @@ public:
virtual String extraQuirksStyleSheet() { return String(); }
#if ENABLE(VIDEO)
virtual String extraMediaControlsStyleSheet() { return String(); };
+#if ENABLE(FULLSCREEN_API)
+ virtual String extraFullScreenStyleSheet() { return String(); };
+#endif
#endif
// A method to obtain the baseline position for a "leaf" control. This will only be used if a baseline
diff --git a/Source/WebCore/rendering/RenderThemeChromiumWin.cpp b/Source/WebCore/rendering/RenderThemeChromiumWin.cpp
index 6f3be00..53ec9cb 100644
--- a/Source/WebCore/rendering/RenderThemeChromiumWin.cpp
+++ b/Source/WebCore/rendering/RenderThemeChromiumWin.cpp
@@ -43,8 +43,8 @@
#include "RenderProgress.h"
#include "RenderSlider.h"
#include "ScrollbarTheme.h"
+#include "SystemInfo.h"
#include "TransparencyWin.h"
-#include "WindowsVersion.h"
// FIXME: This dependency should eventually be removed.
#include <skia/ext/skia_utils_win.h>
@@ -141,8 +141,8 @@ bool ThemePainter::s_hasInstance = false;
static void getNonClientMetrics(NONCLIENTMETRICS* metrics)
{
- static UINT size = isVistaOrNewer() ?
- sizeof(NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA;
+ static UINT size = (windowsVersion() >= WindowsVista) ?
+ (sizeof NONCLIENTMETRICS) : NONCLIENTMETRICS_SIZE_PRE_VISTA;
metrics->cbSize = size;
bool success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, size, metrics, 0);
ASSERT(success);
diff --git a/Source/WebCore/rendering/RenderThemeMac.h b/Source/WebCore/rendering/RenderThemeMac.h
index d951ff6..d64944b 100644
--- a/Source/WebCore/rendering/RenderThemeMac.h
+++ b/Source/WebCore/rendering/RenderThemeMac.h
@@ -162,6 +162,9 @@ protected:
// Media controls
virtual String extraMediaControlsStyleSheet();
+#if ENABLE(FULLSCREEN_API)
+ virtual String extraFullScreenStyleSheet();
+#endif
virtual bool shouldRenderMediaControlPart(ControlPart, Element*);
virtual bool usesMediaControlStatusDisplay();
diff --git a/Source/WebCore/rendering/RenderThemeMac.mm b/Source/WebCore/rendering/RenderThemeMac.mm
index f5611dc..0e23c89 100644
--- a/Source/WebCore/rendering/RenderThemeMac.mm
+++ b/Source/WebCore/rendering/RenderThemeMac.mm
@@ -1961,20 +1961,45 @@ String RenderThemeMac::extraMediaControlsStyleSheet()
#endif
}
+#if ENABLE(FULLSCREEN_API)
+String RenderThemeMac::extraFullScreenStyleSheet()
+{
+#if PLATFORM(MAC)
+ if (mediaControllerTheme() == MediaControllerThemeQuickTime)
+ return String(fullscreenQuickTimeUserAgentStyleSheet, sizeof(fullscreenQuickTimeUserAgentStyleSheet));
+
+ return String();
+#else
+ ASSERT_NOT_REACHED();
+ return String();
+#endif
+}
+#endif
+
bool RenderThemeMac::shouldRenderMediaControlPart(ControlPart part, Element* element)
{
+ HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element);
switch (part) {
case MediaVolumeSliderContainerPart:
case MediaVolumeSliderPart:
case MediaVolumeSliderMuteButtonPart:
case MediaVolumeSliderThumbPart: {
- HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(element);
return mediaControllerTheme() == MediaControllerThemeQuickTime && mediaElement->hasAudio();
}
case MediaToggleClosedCaptionsButtonPart:
// We rely on QTKit to render captions so don't enable the button unless it will be able to do so.
if (!element->hasTagName(videoTag))
return false;
+ break;
+ case MediaRewindButtonPart:
+ if (mediaElement->isFullscreen())
+ return mediaElement->movieLoadType() == MediaPlayer::LiveStream
+ || mediaElement->movieLoadType() == MediaPlayer::StoredStream;
+ case MediaSeekForwardButtonPart:
+ case MediaSeekBackButtonPart:
+ if (mediaElement->isFullscreen())
+ return mediaElement->movieLoadType() != MediaPlayer::StoredStream
+ && mediaElement->movieLoadType() != MediaPlayer::LiveStream;
default:
break;
}
diff --git a/Source/WebCore/rendering/RenderThemeWin.cpp b/Source/WebCore/rendering/RenderThemeWin.cpp
index d5e4155..af100b7 100644
--- a/Source/WebCore/rendering/RenderThemeWin.cpp
+++ b/Source/WebCore/rendering/RenderThemeWin.cpp
@@ -569,15 +569,17 @@ ThemeData RenderThemeWin::getThemeData(RenderObject* o, ControlSubPart subPart)
result.m_state = determineState(o);
break;
case MenulistPart:
- case MenulistButtonPart:
- result.m_part = isRunningOnVistaOrLater() ? CP_DROPDOWNBUTTONRIGHT : CP_DROPDOWNBUTTON;
- if (isRunningOnVistaOrLater() && documentIsInApplicationChromeMode(o->document())) {
+ case MenulistButtonPart: {
+ const bool isVistaOrLater = (windowsVersion() >= WindowsVista);
+ result.m_part = isVistaOrLater ? CP_DROPDOWNBUTTONRIGHT : CP_DROPDOWNBUTTON;
+ if (isVistaOrLater && documentIsInApplicationChromeMode(o->document())) {
// The "readonly" look we use in application chrome mode
// only uses a "normal" look for the drop down button.
result.m_state = TS_NORMAL;
} else
result.m_state = determineState(o);
break;
+ }
case RadioPart:
result.m_part = BP_RADIO;
result.m_state = determineState(o);
@@ -585,7 +587,7 @@ ThemeData RenderThemeWin::getThemeData(RenderObject* o, ControlSubPart subPart)
case SearchFieldPart:
case TextFieldPart:
case TextAreaPart:
- result.m_part = isRunningOnVistaOrLater() ? EP_EDITBORDER_NOSCROLL : TFP_TEXTFIELD;
+ result.m_part = (windowsVersion() >= WindowsVista) ? EP_EDITBORDER_NOSCROLL : TFP_TEXTFIELD;
result.m_state = determineState(o);
break;
case SliderHorizontalPart:
@@ -728,7 +730,7 @@ bool RenderThemeWin::paintMenuList(RenderObject* o, const PaintInfo& i, const In
{
HANDLE theme;
int part;
- if (haveTheme && isRunningOnVistaOrLater()) {
+ if (haveTheme && (windowsVersion() >= WindowsVista)) {
theme = menuListTheme();
if (documentIsInApplicationChromeMode(o->document()))
part = CP_READONLY;
@@ -792,7 +794,7 @@ bool RenderThemeWin::paintMenuListButton(RenderObject* o, const PaintInfo& i, co
buttonRect.setX(buttonRect.maxX() - dropDownButtonWidth);
buttonRect.setWidth(dropDownButtonWidth);
- if (isRunningOnVistaOrLater()) {
+ if ((windowsVersion() >= WindowsVista)) {
// Outset the top, right, and bottom borders of the button so that they coincide with the <select>'s border.
buttonRect.setY(buttonRect.y() - vistaMenuListButtonOutset);
buttonRect.setHeight(buttonRect.height() + 2 * vistaMenuListButtonOutset);
diff --git a/Source/WebCore/rendering/RenderTreeAsText.cpp b/Source/WebCore/rendering/RenderTreeAsText.cpp
index cad5830..8857391 100644
--- a/Source/WebCore/rendering/RenderTreeAsText.cpp
+++ b/Source/WebCore/rendering/RenderTreeAsText.cpp
@@ -35,6 +35,7 @@
#include "InlineTextBox.h"
#include "PrintContext.h"
#include "RenderBR.h"
+#include "RenderDetailsMarker.h"
#include "RenderFileUploadControl.h"
#include "RenderInline.h"
#include "RenderLayer.h"
@@ -45,6 +46,7 @@
#include "RenderView.h"
#include "RenderWidget.h"
#include "SelectionController.h"
+#include <wtf/HexNumber.h>
#include <wtf/UnusedParam.h>
#include <wtf/Vector.h>
#include <wtf/unicode/CharacterNames.h>
@@ -209,11 +211,11 @@ String quoteAndEscapeNonPrintables(const String& s)
if (c >= 0x20 && c < 0x7F)
result.append(c);
else {
- unsigned u = c;
- String hex = String::format("\\x{%X}", u);
- unsigned len = hex.length();
- for (unsigned i = 0; i < len; ++i)
- result.append(hex[i]);
+ result.append('\\');
+ result.append('x');
+ result.append('{');
+ appendUnsignedAsHex(c, result);
+ result.append('}');
}
}
}
@@ -372,6 +374,24 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o,
ts << " [r=" << c.row() << " c=" << c.col() << " rs=" << c.rowSpan() << " cs=" << c.colSpan() << "]";
}
+ if (o.isDetailsMarker()) {
+ ts << ": ";
+ switch (toRenderDetailsMarker(&o)->orientation()) {
+ case RenderDetailsMarker::Left:
+ ts << "left";
+ break;
+ case RenderDetailsMarker::Right:
+ ts << "right";
+ break;
+ case RenderDetailsMarker::Up:
+ ts << "up";
+ break;
+ case RenderDetailsMarker::Down:
+ ts << "down";
+ break;
+ }
+ }
+
if (o.isListMarker()) {
String text = toRenderListMarker(&o)->text();
if (!text.isEmpty()) {
@@ -487,8 +507,10 @@ static void writeTextRun(TextStream& ts, const RenderText& o, const InlineTextBo
ts << " override";
}
ts << ": "
- << quoteAndEscapeNonPrintables(String(o.text()).substring(run.start(), run.len()))
- << "\n";
+ << quoteAndEscapeNonPrintables(String(o.text()).substring(run.start(), run.len()));
+ if (run.hasHyphen())
+ ts << " + hyphen string " << quoteAndEscapeNonPrintables(o.style()->hyphenString());
+ ts << "\n";
}
void write(TextStream& ts, const RenderObject& o, int indent, RenderAsTextBehavior behavior)
diff --git a/Source/WebCore/rendering/RenderVideo.cpp b/Source/WebCore/rendering/RenderVideo.cpp
index 1ae736b..3a96ef8 100644
--- a/Source/WebCore/rendering/RenderVideo.cpp
+++ b/Source/WebCore/rendering/RenderVideo.cpp
@@ -202,6 +202,8 @@ void RenderVideo::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
if (displayingPoster)
paintIntoRect(paintInfo.context, rect);
+ else if (document()->view() && document()->view()->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
+ mediaPlayer->paintCurrentFrameInContext(paintInfo.context, rect);
else
mediaPlayer->paint(paintInfo.context, rect);
}
diff --git a/Source/WebCore/rendering/RenderWidget.cpp b/Source/WebCore/rendering/RenderWidget.cpp
index 13b572d..33f6436 100644
--- a/Source/WebCore/rendering/RenderWidget.cpp
+++ b/Source/WebCore/rendering/RenderWidget.cpp
@@ -136,7 +136,7 @@ void RenderWidget::destroy()
if (hasOverrideSize())
setOverrideSize(-1);
- if (style() && (style()->height().isPercent() || style()->minHeight().isPercent() || style()->maxHeight().isPercent()))
+ if (style() && (style()->logicalHeight().isPercent() || style()->logicalMinHeight().isPercent() || style()->logicalMaxHeight().isPercent()))
RenderBlock::removePercentHeightDescendant(this);
if (hasLayer()) {
diff --git a/Source/WebCore/rendering/RootInlineBox.cpp b/Source/WebCore/rendering/RootInlineBox.cpp
index 8617252..c6f1bd8 100644
--- a/Source/WebCore/rendering/RootInlineBox.cpp
+++ b/Source/WebCore/rendering/RootInlineBox.cpp
@@ -28,10 +28,12 @@
#include "Frame.h"
#include "GraphicsContext.h"
#include "HitTestResult.h"
+#include "InlineTextBox.h"
#include "Page.h"
#include "PaintInfo.h"
#include "RenderArena.h"
#include "RenderBlock.h"
+#include "VerticalPositionCache.h"
using namespace std;
@@ -52,7 +54,7 @@ RootInlineBox::RootInlineBox(RenderBlock* block)
, m_hasAnnotationsBefore(false)
, m_hasAnnotationsAfter(false)
{
- setIsHorizontal(block->style()->isHorizontalWritingMode());
+ setIsHorizontal(block->isHorizontalWritingMode());
}
@@ -238,7 +240,7 @@ int RootInlineBox::alignBoxesInBlockDirection(int heightOfBlock, GlyphOverflowAn
m_baselineType = requiresIdeographicBaseline(textBoxDataMap) ? IdeographicBaseline : AlphabeticBaseline;
- computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, setMaxAscent, setMaxDescent, noQuirksMode,
+ computeLogicalBoxHeights(this, maxPositionTop, maxPositionBottom, maxAscent, maxDescent, setMaxAscent, setMaxDescent, noQuirksMode,
textBoxDataMap, baselineType(), verticalPositionCache);
if (maxAscent + maxDescent < max(maxPositionTop, maxPositionBottom))
@@ -335,7 +337,7 @@ GapRects RootInlineBox::lineSelectionGap(RenderBlock* rootBlock, const IntPoint&
for (InlineBox* box = firstBox->nextLeafChild(); box; box = box->nextLeafChild()) {
if (box->selectionState() != RenderObject::SelectionNone) {
IntRect logicalRect(lastLogicalLeft, selTop, box->logicalLeft() - lastLogicalLeft, selHeight);
- logicalRect.move(renderer()->style()->isHorizontalWritingMode() ? offsetFromRootBlock : IntSize(offsetFromRootBlock.height(), offsetFromRootBlock.width()));
+ logicalRect.move(renderer()->isHorizontalWritingMode() ? offsetFromRootBlock : IntSize(offsetFromRootBlock.height(), offsetFromRootBlock.width()));
IntRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
if (isPreviousBoxSelected && gapRect.width() > 0 && gapRect.height() > 0) {
if (paintInfo && box->parent()->renderer()->style()->visibility() == VISIBLE)
@@ -354,13 +356,6 @@ GapRects RootInlineBox::lineSelectionGap(RenderBlock* rootBlock, const IntPoint&
return result;
}
-void RootInlineBox::setHasSelectedChildren(bool b)
-{
- if (m_hasSelectedChildren == b)
- return;
- m_hasSelectedChildren = b;
-}
-
RenderObject::SelectionState RootInlineBox::selectionState()
{
// Walk over all of the selected boxes.
@@ -460,7 +455,7 @@ RenderBlock* RootInlineBox::block() const
static bool isEditableLeaf(InlineBox* leaf)
{
- return leaf && leaf->renderer() && leaf->renderer()->node() && leaf->renderer()->node()->isContentEditable();
+ return leaf && leaf->renderer() && leaf->renderer()->node() && leaf->renderer()->node()->rendererIsEditable();
}
InlineBox* RootInlineBox::closestLeafChildForLogicalLeftPosition(int leftPosition, bool onlyEditableLeaves)
@@ -553,4 +548,269 @@ IntRect RootInlineBox::paddedLayoutOverflowRect(int endPadding) const
return lineLayoutOverflow;
}
+static void setAscentAndDescent(int& ascent, int& descent, int newAscent, int newDescent, bool& ascentDescentSet)
+{
+ if (!ascentDescentSet) {
+ ascentDescentSet = true;
+ ascent = newAscent;
+ descent = newDescent;
+ } else {
+ ascent = max(ascent, newAscent);
+ descent = max(descent, newDescent);
+ }
+}
+
+void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, int& ascent, int& descent,
+ bool& affectsAscent, bool& affectsDescent) const
+{
+ bool ascentDescentSet = false;
+
+ // Replaced boxes will return 0 for the line-height if line-box-contain says they are
+ // not to be included.
+ if (box->renderer()->isReplaced()) {
+ if (renderer()->style(m_firstLine)->lineBoxContain() & LineBoxContainReplaced) {
+ ascent = box->baselinePosition(baselineType());
+ descent = box->lineHeight() - ascent;
+
+ // Replaced elements always affect both the ascent and descent.
+ affectsAscent = true;
+ affectsDescent = true;
+ }
+ return;
+ }
+
+ Vector<const SimpleFontData*>* usedFonts = 0;
+ GlyphOverflow* glyphOverflow = 0;
+ if (box->isText()) {
+ GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(static_cast<InlineTextBox*>(box));
+ usedFonts = it == textBoxDataMap.end() ? 0 : &it->second.first;
+ glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->second.second;
+ }
+
+ bool includeLeading = includeLeadingForBox(box);
+ bool includeFont = includeFontForBox(box);
+
+ bool setUsedFont = false;
+ bool setUsedFontWithLeading = false;
+
+ if (usedFonts && !usedFonts->isEmpty() && (includeFont || (box->renderer()->style(m_firstLine)->lineHeight().isNegative() && includeLeading))) {
+ usedFonts->append(box->renderer()->style(m_firstLine)->font().primaryFont());
+ for (size_t i = 0; i < usedFonts->size(); ++i) {
+ const FontMetrics& fontMetrics = usedFonts->at(i)->fontMetrics();
+ int usedFontAscent = fontMetrics.ascent(baselineType());
+ int usedFontDescent = fontMetrics.descent(baselineType());
+ int halfLeading = (fontMetrics.lineSpacing() - fontMetrics.height()) / 2;
+ int usedFontAscentAndLeading = usedFontAscent + halfLeading;
+ int usedFontDescentAndLeading = fontMetrics.lineSpacing() - usedFontAscentAndLeading;
+ if (includeFont) {
+ setAscentAndDescent(ascent, descent, usedFontAscent, usedFontDescent, ascentDescentSet);
+ setUsedFont = true;
+ }
+ if (includeLeading) {
+ setAscentAndDescent(ascent, descent, usedFontAscentAndLeading, usedFontDescentAndLeading, ascentDescentSet);
+ setUsedFontWithLeading = true;
+ }
+ if (!affectsAscent)
+ affectsAscent = usedFontAscent - box->logicalTop() > 0;
+ if (!affectsDescent)
+ affectsDescent = usedFontDescent + box->logicalTop() > 0;
+ }
+ }
+
+ // If leading is included for the box, then we compute that box.
+ if (includeLeading && !setUsedFontWithLeading) {
+ int ascentWithLeading = box->baselinePosition(baselineType());
+ int descentWithLeading = box->lineHeight() - ascentWithLeading;
+ setAscentAndDescent(ascent, descent, ascentWithLeading, descentWithLeading, ascentDescentSet);
+
+ // Examine the font box for inline flows and text boxes to see if any part of it is above the baseline.
+ // If the top of our font box relative to the root box baseline is above the root box baseline, then
+ // we are contributing to the maxAscent value. Descent is similar. If any part of our font box is below
+ // the root box's baseline, then we contribute to the maxDescent value.
+ affectsAscent = ascentWithLeading - box->logicalTop() > 0;
+ affectsDescent = descentWithLeading + box->logicalTop() > 0;
+ }
+
+ if (includeFontForBox(box) && !setUsedFont) {
+ int fontAscent = box->renderer()->style(m_firstLine)->fontMetrics().ascent();
+ int fontDescent = box->renderer()->style(m_firstLine)->fontMetrics().descent();
+ setAscentAndDescent(ascent, descent, fontAscent, fontDescent, ascentDescentSet);
+ affectsAscent = fontAscent - box->logicalTop() > 0;
+ affectsDescent = fontDescent + box->logicalTop() > 0;
+ }
+
+ if (includeGlyphsForBox(box) && glyphOverflow && glyphOverflow->computeBounds) {
+ setAscentAndDescent(ascent, descent, glyphOverflow->top, glyphOverflow->bottom, ascentDescentSet);
+ affectsAscent = glyphOverflow->top - box->logicalTop() > 0;
+ affectsDescent = glyphOverflow->bottom + box->logicalTop() > 0;
+ glyphOverflow->top = min(glyphOverflow->top, max(0, glyphOverflow->top - box->renderer()->style(m_firstLine)->fontMetrics().ascent()));
+ glyphOverflow->bottom = min(glyphOverflow->bottom, max(0, glyphOverflow->bottom - box->renderer()->style(m_firstLine)->fontMetrics().descent()));
+ }
+
+ if (includeMarginForBox(box)) {
+ int ascentWithMargin = box->renderer()->style(m_firstLine)->fontMetrics().ascent();
+ int descentWithMargin = box->renderer()->style(m_firstLine)->fontMetrics().descent();
+ if (box->parent() && !box->renderer()->isText()) {
+ ascentWithMargin += box->boxModelObject()->borderBefore() + box->boxModelObject()->paddingBefore() + box->boxModelObject()->marginBefore();
+ descentWithMargin += box->boxModelObject()->borderAfter() + box->boxModelObject()->paddingAfter() + box->boxModelObject()->marginAfter();
+ }
+ setAscentAndDescent(ascent, descent, ascentWithMargin, descentWithMargin, ascentDescentSet);
+
+ // Treat like a replaced element, since we're using the margin box.
+ affectsAscent = true;
+ affectsDescent = true;
+ }
+}
+
+int RootInlineBox::verticalPositionForBox(InlineBox* box, VerticalPositionCache& verticalPositionCache)
+{
+ if (box->renderer()->isText())
+ return box->parent()->logicalTop();
+
+ RenderBoxModelObject* renderer = box->boxModelObject();
+ ASSERT(renderer->isInline());
+ if (!renderer->isInline())
+ return 0;
+
+ // This method determines the vertical position for inline elements.
+ bool firstLine = m_firstLine;
+ if (firstLine && !renderer->document()->usesFirstLineRules())
+ firstLine = false;
+
+ // Check the cache.
+ bool isRenderInline = renderer->isRenderInline();
+ if (isRenderInline && !firstLine) {
+ int verticalPosition = verticalPositionCache.get(renderer, baselineType());
+ if (verticalPosition != PositionUndefined)
+ return verticalPosition;
+ }
+
+ int verticalPosition = 0;
+ EVerticalAlign verticalAlign = renderer->style()->verticalAlign();
+ if (verticalAlign == TOP || verticalAlign == BOTTOM)
+ return 0;
+
+ RenderObject* parent = renderer->parent();
+ if (parent->isRenderInline() && parent->style()->verticalAlign() != TOP && parent->style()->verticalAlign() != BOTTOM)
+ verticalPosition = box->parent()->logicalTop();
+
+ if (verticalAlign != BASELINE) {
+ const Font& font = parent->style(firstLine)->font();
+ const FontMetrics& fontMetrics = font.fontMetrics();
+ int fontSize = font.pixelSize();
+
+ LineDirectionMode lineDirection = parent->isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
+
+ if (verticalAlign == SUB)
+ verticalPosition += fontSize / 5 + 1;
+ else if (verticalAlign == SUPER)
+ verticalPosition -= fontSize / 3 + 1;
+ else if (verticalAlign == TEXT_TOP)
+ verticalPosition += renderer->baselinePosition(baselineType(), firstLine, lineDirection) - fontMetrics.ascent(baselineType());
+ else if (verticalAlign == MIDDLE)
+ verticalPosition += -static_cast<int>(fontMetrics.xHeight() / 2) - renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType(), firstLine, lineDirection);
+ else if (verticalAlign == TEXT_BOTTOM) {
+ verticalPosition += fontMetrics.descent(baselineType());
+ // lineHeight - baselinePosition is always 0 for replaced elements (except inline blocks), so don't bother wasting time in that case.
+ if (!renderer->isReplaced() || renderer->isInlineBlockOrInlineTable())
+ verticalPosition -= (renderer->lineHeight(firstLine, lineDirection) - renderer->baselinePosition(baselineType(), firstLine, lineDirection));
+ } else if (verticalAlign == BASELINE_MIDDLE)
+ verticalPosition += -renderer->lineHeight(firstLine, lineDirection) / 2 + renderer->baselinePosition(baselineType(), firstLine, lineDirection);
+ else if (verticalAlign == LENGTH)
+ verticalPosition -= renderer->style()->verticalAlignLength().calcValue(renderer->lineHeight(firstLine, lineDirection));
+ }
+
+ // Store the cached value.
+ if (isRenderInline && !firstLine)
+ verticalPositionCache.set(renderer, baselineType(), verticalPosition);
+
+ return verticalPosition;
+}
+
+bool RootInlineBox::includeLeadingForBox(InlineBox* box) const
+{
+ if (box->renderer()->isReplaced() || (box->renderer()->isText() && !box->isText()))
+ return false;
+
+ LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain();
+ return (lineBoxContain & LineBoxContainInline) || (box == this && (lineBoxContain & LineBoxContainBlock));
+}
+
+bool RootInlineBox::includeFontForBox(InlineBox* box) const
+{
+ if (box->renderer()->isReplaced() || (box->renderer()->isText() && !box->isText()))
+ return false;
+
+ if (!box->isText() && box->isInlineFlowBox() && !static_cast<InlineFlowBox*>(box)->hasTextChildren())
+ return false;
+
+ // For now map "glyphs" to "font" in vertical text mode until the bounds returned by glyphs aren't garbage.
+ LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain();
+ return (lineBoxContain & LineBoxContainFont) || (!isHorizontal() && (lineBoxContain & LineBoxContainGlyphs));
+}
+
+bool RootInlineBox::includeGlyphsForBox(InlineBox* box) const
+{
+ if (box->renderer()->isReplaced() || (box->renderer()->isText() && !box->isText()))
+ return false;
+
+ if (!box->isText() && box->isInlineFlowBox() && !static_cast<InlineFlowBox*>(box)->hasTextChildren())
+ return false;
+
+ // FIXME: We can't fit to glyphs yet for vertical text, since the bounds returned are garbage.
+ LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain();
+ return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs);
+}
+
+bool RootInlineBox::includeMarginForBox(InlineBox* box) const
+{
+ if (box->renderer()->isReplaced() || (box->renderer()->isText() && !box->isText()))
+ return false;
+
+ LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain();
+ return lineBoxContain & LineBoxContainInlineBox;
+}
+
+
+bool RootInlineBox::fitsToGlyphs() const
+{
+ // FIXME: We can't fit to glyphs yet for vertical text, since the bounds returned are garbage.
+ LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain();
+ return isHorizontal() && (lineBoxContain & LineBoxContainGlyphs);
+}
+
+bool RootInlineBox::includesRootLineBoxFontOrLeading() const
+{
+ LineBoxContain lineBoxContain = renderer()->style()->lineBoxContain();
+ return (lineBoxContain & LineBoxContainBlock) || (lineBoxContain & LineBoxContainInline) || (lineBoxContain & LineBoxContainFont);
+}
+
+Node* RootInlineBox::getLogicalStartBoxWithNode(InlineBox*& startBox)
+{
+ Vector<InlineBox*> leafBoxesInLogicalOrder;
+ collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder);
+ for (size_t i = 0; i < leafBoxesInLogicalOrder.size(); ++i) {
+ if (leafBoxesInLogicalOrder[i]->renderer()->node()) {
+ startBox = leafBoxesInLogicalOrder[i];
+ return startBox->renderer()->node();
+ }
+ }
+ startBox = 0;
+ return 0;
+}
+
+Node* RootInlineBox::getLogicalEndBoxWithNode(InlineBox*& endBox)
+{
+ Vector<InlineBox*> leafBoxesInLogicalOrder;
+ collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder);
+ for (size_t i = leafBoxesInLogicalOrder.size(); i > 0; --i) {
+ if (leafBoxesInLogicalOrder[i - 1]->renderer()->node()) {
+ endBox = leafBoxesInLogicalOrder[i - 1];
+ return endBox->renderer()->node();
+ }
+ }
+ endBox = 0;
+ return 0;
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/rendering/RootInlineBox.h b/Source/WebCore/rendering/RootInlineBox.h
index 1a9f0a8..0ff5704 100644
--- a/Source/WebCore/rendering/RootInlineBox.h
+++ b/Source/WebCore/rendering/RootInlineBox.h
@@ -99,8 +99,8 @@ public:
virtual void paint(PaintInfo&, int tx, int ty);
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int, int, int, int);
- bool hasSelectedChildren() const { return m_hasSelectedChildren; }
- void setHasSelectedChildren(bool);
+ bool hasSelectedChildren() const { return m_hasSelectedChildrenOrCanHaveLeadingExpansion; }
+ void setHasSelectedChildren(bool hasSelectedChildren) { m_hasSelectedChildrenOrCanHaveLeadingExpansion = hasSelectedChildren; }
virtual RenderObject::SelectionState selectionState();
InlineBox* firstSelectedBox();
@@ -133,6 +133,17 @@ public:
IntRect paddedLayoutOverflowRect(int endPadding) const;
+ void ascentAndDescentForBox(InlineBox*, GlyphOverflowAndFallbackFontsMap&, int& ascent, int& descent, bool& affectsAscent, bool& affectsDescent) const;
+ int verticalPositionForBox(InlineBox*, VerticalPositionCache&);
+ bool includeLeadingForBox(InlineBox*) const;
+ bool includeFontForBox(InlineBox*) const;
+ bool includeGlyphsForBox(InlineBox*) const;
+ bool includeMarginForBox(InlineBox*) const;
+ bool fitsToGlyphs() const;
+ bool includesRootLineBoxFontOrLeading() const;
+
+ Node* getLogicalStartBoxWithNode(InlineBox*&);
+ Node* getLogicalEndBoxWithNode(InlineBox*&);
private:
bool hasEllipsisBox() const { return m_hasEllipsisBoxOrHyphen; }
void setHasEllipsisBox(bool hasEllipsisBox) { m_hasEllipsisBoxOrHyphen = hasEllipsisBox; }
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp b/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp
index 075f6ba..51046f8 100644
--- a/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp
+++ b/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp
@@ -229,7 +229,10 @@ void RenderMathMLRoot::layout()
}
// Positioning of the index
- RenderBoxModelObject* indexBox = toRenderBoxModelObject(firstChild()->firstChild());
+ RenderObject* possibleIndex = firstChild()->firstChild();
+ while (possibleIndex && !possibleIndex->isBoxModelObject())
+ possibleIndex = possibleIndex->nextSibling();
+ RenderBoxModelObject* indexBox = toRenderBoxModelObject(possibleIndex);
if (!indexBox)
return;
diff --git a/Source/WebCore/rendering/style/BorderData.h b/Source/WebCore/rendering/style/BorderData.h
index 0e50edb..26f089f 100644
--- a/Source/WebCore/rendering/style/BorderData.h
+++ b/Source/WebCore/rendering/style/BorderData.h
@@ -49,13 +49,13 @@ public:
bool hasBorderRadius() const
{
- if (m_topLeft.width().rawValue() > 0)
+ if (!m_topLeft.width().isZero())
return true;
- if (m_topRight.width().rawValue() > 0)
+ if (!m_topRight.width().isZero())
return true;
- if (m_bottomLeft.width().rawValue() > 0)
+ if (!m_bottomLeft.width().isZero())
return true;
- if (m_bottomRight.width().rawValue() > 0)
+ if (!m_bottomRight.width().isZero())
return true;
return false;
}
diff --git a/Source/WebCore/rendering/style/FillLayer.cpp b/Source/WebCore/rendering/style/FillLayer.cpp
index 59f3bb2..c957cfe 100644
--- a/Source/WebCore/rendering/style/FillLayer.cpp
+++ b/Source/WebCore/rendering/style/FillLayer.cpp
@@ -129,17 +129,6 @@ bool FillLayer::operator==(const FillLayer& o) const
void FillLayer::fillUnsetProperties()
{
FillLayer* curr;
- for (curr = this; curr && curr->isImageSet(); curr = curr->next()) { }
- if (curr && curr != this) {
- // We need to fill in the remaining values with the pattern specified.
- for (FillLayer* pattern = this; curr; curr = curr->next()) {
- curr->m_image = pattern->m_image;
- pattern = pattern->next();
- if (pattern == curr || !pattern)
- pattern = this;
- }
- }
-
for (curr = this; curr && curr->isXPositionSet(); curr = curr->next()) { }
if (curr && curr != this) {
// We need to fill in the remaining values with the pattern specified.
@@ -246,12 +235,7 @@ void FillLayer::cullEmptyLayers()
FillLayer* next;
for (FillLayer* p = this; p; p = next) {
next = p->m_next;
- if (next && !next->isImageSet() &&
- !next->isXPositionSet() && !next->isYPositionSet() &&
- !next->isAttachmentSet() && !next->isClipSet() &&
- !next->isCompositeSet() && !next->isOriginSet() &&
- !next->isRepeatXSet() && !next->isRepeatYSet()
- && !next->isSizeSet()) {
+ if (next && !next->isImageSet()) {
delete next;
p->m_next = 0;
break;
diff --git a/Source/WebCore/rendering/style/RenderStyle.cpp b/Source/WebCore/rendering/style/RenderStyle.cpp
index 122b762..34e972d 100644
--- a/Source/WebCore/rendering/style/RenderStyle.cpp
+++ b/Source/WebCore/rendering/style/RenderStyle.cpp
@@ -56,6 +56,14 @@ PassRefPtr<RenderStyle> RenderStyle::createDefaultStyle()
return adoptRef(new RenderStyle(true));
}
+PassRefPtr<RenderStyle> RenderStyle::createAnonymousStyle(const RenderStyle* parentStyle)
+{
+ RefPtr<RenderStyle> newStyle = RenderStyle::create();
+ newStyle->inheritFrom(parentStyle);
+ newStyle->inheritUnicodeBidiFrom(parentStyle);
+ return newStyle;
+}
+
PassRefPtr<RenderStyle> RenderStyle::clone(const RenderStyle* other)
{
return adoptRef(new RenderStyle(*other));
@@ -295,21 +303,6 @@ static bool positionedObjectMoved(const LengthBox& a, const LengthBox& b)
return true;
}
-/*
- compares two styles. The result gives an idea of the action that
- needs to be taken when replacing the old style with a new one.
-
- CbLayout: The containing block of the object needs a relayout.
- Layout: the RenderObject needs a relayout after the style change
- Visible: The change is visible, but no relayout is needed
- NonVisible: The object does need neither repaint nor relayout after
- the change.
-
- ### TODO:
- A lot can be optimised here based on the display type, lots of
- optimisations are unimplemented, and currently result in the
- worst case result causing a relayout of the containing block.
-*/
StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedContextSensitiveProperties) const
{
changedContextSensitiveProperties = ContextSensitivePropertyNone;
@@ -411,7 +404,8 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
rareInheritedData->locale != other->rareInheritedData->locale ||
rareInheritedData->textEmphasisMark != other->rareInheritedData->textEmphasisMark ||
rareInheritedData->textEmphasisPosition != other->rareInheritedData->textEmphasisPosition ||
- rareInheritedData->textEmphasisCustomMark != other->rareInheritedData->textEmphasisCustomMark)
+ rareInheritedData->textEmphasisCustomMark != other->rareInheritedData->textEmphasisCustomMark ||
+ rareInheritedData->m_lineBoxContain != other->rareInheritedData->m_lineBoxContain)
return StyleDifferenceLayout;
if (!rareInheritedData->shadowDataEquivalent(*other->rareInheritedData.get()))
@@ -499,15 +493,19 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
rareNonInheritedData->m_counterReset != other->rareNonInheritedData->m_counterReset)
return StyleDifferenceLayout;
+ if ((visibility() == COLLAPSE) != (other->visibility() == COLLAPSE))
+ return StyleDifferenceLayout;
+
if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1) ||
(rareNonInheritedData->opacity < 1 && other->rareNonInheritedData->opacity == 1)) {
- // FIXME: We should add an optimized form of layout that just recomputes visual overflow.
+ // FIXME: We would like to use SimplifiedLayout here, but we can't quite do that yet.
+ // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
+ // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
+ // In addition we need to solve the floating object issue when layers come and go. Right now
+ // a full layout is necessary to keep floating object lists sane.
return StyleDifferenceLayout;
}
- 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,
@@ -525,13 +523,10 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon
if (position() == AbsolutePosition && positionedObjectMoved(surround->offset, other->surround->offset))
return StyleDifferenceLayoutPositionedMovementOnly;
- // FIXME: We will need to do a bit of work in RenderObject/Box::setStyle before we
- // can stop doing a layout when relative positioned objects move. In particular, we'll need
- // to update scrolling positions and figure out how to do a repaint properly of the updated layer.
- //if (other->position() == RelativePosition)
- // return RepaintLayer;
- //else
- return StyleDifferenceLayout;
+ // FIXME: We would like to use SimplifiedLayout for relative positioning, but we can't quite do that yet.
+ // We need to make sure SimplifiedLayout can operate correctly on RenderInlines (we will need
+ // to add a selfNeedsSimplifiedLayout bit in order to not get confused and taint every line).
+ return StyleDifferenceLayout;
} else if (m_box->zIndex() != other->m_box->zIndex() || m_box->hasAutoZIndex() != other->m_box->hasAutoZIndex() ||
visual->clip != other->visual->clip || visual->hasClip != other->visual->hasClip)
return StyleDifferenceRepaintLayer;
diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h
index 79ed6e4..859348f 100644
--- a/Source/WebCore/rendering/style/RenderStyle.h
+++ b/Source/WebCore/rendering/style/RenderStyle.h
@@ -27,6 +27,7 @@
#include "AnimationList.h"
#include "BorderValue.h"
+#include "CSSLineBoxContainValue.h"
#include "CSSPrimitiveValue.h"
#include "CSSPropertyNames.h"
#include "Color.h"
@@ -58,6 +59,7 @@
#include "StyleTransformData.h"
#include "StyleVisualData.h"
#include "TextDirection.h"
+#include "TextOrientation.h"
#include "ThemeTypes.h"
#include "TransformOperations.h"
#include <wtf/Forward.h>
@@ -106,6 +108,7 @@ class RenderStyle: public RefCounted<RenderStyle> {
friend class AnimationBase; // Used by CSS animations. We can't allow them to animate based off visited colors.
friend class ApplyStyleCommand; // Editing has to only reveal unvisited info.
friend class EditingStyle; // Editing has to only reveal unvisited info.
+ friend class CSSStyleApplyProperty; // Sets members directly.
friend class CSSStyleSelector; // Sets members directly.
friend class CSSComputedStyleDeclaration; // Ignores visited styles, so needs to be able to see unvisited info.
friend class PropertyWrapperMaybeInvalidColor; // Used by CSS animations. We can't allow them to animate based off visited colors.
@@ -184,7 +187,7 @@ protected:
unsigned _list_style_type : 7; // EListStyleType
unsigned _list_style_position : 1; // EListStylePosition
unsigned _visibility : 2; // EVisibility
- unsigned _text_align : 3; // ETextAlign
+ unsigned _text_align : 4; // ETextAlign
unsigned _text_transform : 2; // ETextTransform
unsigned _text_decorations : 4;
unsigned _cursor_style : 6; // ECursor
@@ -310,6 +313,7 @@ private:
public:
static PassRefPtr<RenderStyle> create();
static PassRefPtr<RenderStyle> createDefaultStyle();
+ static PassRefPtr<RenderStyle> createAnonymousStyle(const RenderStyle* parentStyle);
static PassRefPtr<RenderStyle> clone(const RenderStyle*);
~RenderStyle();
@@ -770,6 +774,7 @@ public:
bool isRunningAcceleratedAnimation() const { return rareNonInheritedData->m_runningAcceleratedAnimation; }
#endif
+ LineBoxContain lineBoxContain() const { return rareInheritedData->m_lineBoxContain; }
const LineClampValue& lineClamp() const { return rareNonInheritedData->lineClamp; }
bool textSizeAdjust() const { return rareInheritedData->textSizeAdjust; }
ETextSecurity textSecurity() const { return static_cast<ETextSecurity>(rareInheritedData->textSecurity); }
@@ -1130,6 +1135,7 @@ public:
void setIsRunningAcceleratedAnimation(bool b = true) { SET_VAR(rareNonInheritedData, m_runningAcceleratedAnimation, b); }
#endif
+ void setLineBoxContain(LineBoxContain c) { SET_VAR(rareInheritedData, m_lineBoxContain, c); }
void setLineClamp(LineClampValue c) { SET_VAR(rareNonInheritedData, lineClamp, c); }
void setTextSizeAdjust(bool b) { SET_VAR(rareInheritedData, textSizeAdjust, b); }
void setTextSecurity(ETextSecurity aTextSecurity) { SET_VAR(rareInheritedData, textSecurity, aTextSecurity); }
@@ -1246,6 +1252,7 @@ public:
static TextDirection initialDirection() { return LTR; }
static WritingMode initialWritingMode() { return TopToBottomWritingMode; }
static TextCombine initialTextCombine() { return TextCombineNone; }
+ static TextOrientation initialTextOrientation() { return TextOrientationVerticalRight; }
static EDisplay initialDisplay() { return INLINE; }
static EEmptyCell initialEmptyCells() { return SHOW; }
static EFloat initialFloating() { return FNONE; }
@@ -1339,6 +1346,7 @@ public:
static TextEmphasisMark initialTextEmphasisMark() { return TextEmphasisMarkNone; }
static const AtomicString& initialTextEmphasisCustomMark() { return nullAtom; }
static TextEmphasisPosition initialTextEmphasisPosition() { return TextEmphasisPositionOver; }
+ static LineBoxContain initialLineBoxContain() { return LineBoxContainBlock | LineBoxContainInline | LineBoxContainReplaced; }
// Keep these at the end.
static LineClampValue initialLineClamp() { return LineClampValue(); }
@@ -1365,6 +1373,7 @@ public:
#endif
private:
+ void inheritUnicodeBidiFrom(const RenderStyle* parent) { noninherited_flags._unicodeBidi = parent->noninherited_flags._unicodeBidi; }
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;
diff --git a/Source/WebCore/rendering/style/RenderStyleConstants.h b/Source/WebCore/rendering/style/RenderStyleConstants.h
index 3c62dbe..08f2c15 100644
--- a/Source/WebCore/rendering/style/RenderStyleConstants.h
+++ b/Source/WebCore/rendering/style/RenderStyleConstants.h
@@ -51,6 +51,7 @@ enum StyleDifference {
StyleDifferenceRepaint,
StyleDifferenceRepaintLayer,
StyleDifferenceLayoutPositionedMovementOnly,
+ StyleDifferenceSimplifiedLayout,
StyleDifferenceLayout
};
@@ -120,7 +121,7 @@ enum ETableLayout {
};
enum EUnicodeBidi {
- UBNormal, Embed, Override
+ UBNormal, Embed, Override, Isolate
};
// CSS Text Layout Module Level 3: Vertical writing support
@@ -318,7 +319,7 @@ enum EWhiteSpace {
};
enum ETextAlign {
- TAAUTO, LEFT, RIGHT, CENTER, JUSTIFY, WEBKIT_LEFT, WEBKIT_RIGHT, WEBKIT_CENTER
+ TAAUTO, LEFT, RIGHT, CENTER, JUSTIFY, WEBKIT_LEFT, WEBKIT_RIGHT, WEBKIT_CENTER, TASTART, TAEND,
};
enum ETextTransform {
diff --git a/Source/WebCore/rendering/style/StyleRareInheritedData.cpp b/Source/WebCore/rendering/style/StyleRareInheritedData.cpp
index 2798fd1..2253d1c 100644
--- a/Source/WebCore/rendering/style/StyleRareInheritedData.cpp
+++ b/Source/WebCore/rendering/style/StyleRareInheritedData.cpp
@@ -66,6 +66,7 @@ StyleRareInheritedData::StyleRareInheritedData()
, textEmphasisFill(TextEmphasisFillFilled)
, textEmphasisMark(TextEmphasisMarkNone)
, textEmphasisPosition(TextEmphasisPositionOver)
+ , m_lineBoxContain(RenderStyle::initialLineBoxContain())
, hyphenationLimitBefore(-1)
, hyphenationLimitAfter(-1)
{
@@ -113,6 +114,7 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o)
, textEmphasisFill(o.textEmphasisFill)
, textEmphasisMark(o.textEmphasisMark)
, textEmphasisPosition(o.textEmphasisPosition)
+ , m_lineBoxContain(o.m_lineBoxContain)
, hyphenationString(o.hyphenationString)
, hyphenationLimitBefore(o.hyphenationLimitBefore)
, hyphenationLimitAfter(o.hyphenationLimitAfter)
@@ -179,6 +181,7 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
&& textEmphasisFill == o.textEmphasisFill
&& textEmphasisMark == o.textEmphasisMark
&& textEmphasisPosition == o.textEmphasisPosition
+ && m_lineBoxContain == o.m_lineBoxContain
&& hyphenationString == o.hyphenationString
&& locale == o.locale
&& textEmphasisCustomMark == o.textEmphasisCustomMark
diff --git a/Source/WebCore/rendering/style/StyleRareInheritedData.h b/Source/WebCore/rendering/style/StyleRareInheritedData.h
index d4f233c..39cfe3c 100644
--- a/Source/WebCore/rendering/style/StyleRareInheritedData.h
+++ b/Source/WebCore/rendering/style/StyleRareInheritedData.h
@@ -99,6 +99,7 @@ public:
unsigned textEmphasisFill : 1; // TextEmphasisFill
unsigned textEmphasisMark : 3; // TextEmphasisMark
unsigned textEmphasisPosition : 1; // TextEmphasisPosition
+ unsigned m_lineBoxContain: 7; // LineBoxContain
AtomicString hyphenationString;
short hyphenationLimitBefore;
diff --git a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h
index 89437f6..268a123 100644
--- a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h
+++ b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h
@@ -107,7 +107,7 @@ public:
short m_counterIncrement;
short m_counterReset;
-
+
#if USE(ACCELERATED_COMPOSITING)
bool m_runningAcceleratedAnimation : 1;
#endif
diff --git a/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp b/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp
index 835bce8..9f3d8a5 100644
--- a/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp
@@ -34,6 +34,7 @@
#include "RenderSVGInline.cpp"
#include "RenderSVGInlineText.cpp"
#include "RenderSVGModelObject.cpp"
+#include "RenderSVGPath.cpp"
#include "RenderSVGResource.cpp"
#include "RenderSVGResourceClipper.cpp"
#include "RenderSVGResourceContainer.cpp"
diff --git a/Source/WebCore/rendering/svg/RenderSVGText.cpp b/Source/WebCore/rendering/svg/RenderSVGText.cpp
index 56d9306..8ca3d58 100644
--- a/Source/WebCore/rendering/svg/RenderSVGText.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGText.cpp
@@ -51,6 +51,7 @@ namespace WebCore {
RenderSVGText::RenderSVGText(SVGTextElement* node)
: RenderSVGBlock(node)
+ , m_needsReordering(false)
, m_needsPositioningValuesUpdate(true)
, m_needsTransformUpdate(true)
{
@@ -127,6 +128,7 @@ void RenderSVGText::layout()
// Perform SVG text layout phase one (see SVGTextLayoutAttributesBuilder for details).
SVGTextLayoutAttributesBuilder layoutAttributesBuilder;
layoutAttributesBuilder.buildLayoutAttributesForTextSubtree(this);
+ m_needsReordering = true;
m_needsPositioningValuesUpdate = false;
updateCachedBoundariesInParents = true;
}
@@ -134,7 +136,7 @@ void RenderSVGText::layout()
// 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.
ASSERT(!isInline());
- ASSERT(!layoutOnlyPositionedObjects());
+ ASSERT(!simplifiedLayout());
ASSERT(!scrollsOverflow());
ASSERT(!hasControlClip());
ASSERT(!hasColumns());
@@ -150,6 +152,9 @@ void RenderSVGText::layout()
ASSERT(childrenInline());
forceLayoutInlineChildren();
+ if (m_needsReordering)
+ m_needsReordering = false;
+
if (!updateCachedBoundariesInParents)
updateCachedBoundariesInParents = oldBoundaries != objectBoundingBox();
diff --git a/Source/WebCore/rendering/svg/RenderSVGText.h b/Source/WebCore/rendering/svg/RenderSVGText.h
index 188d5fc..93fc5f8 100644
--- a/Source/WebCore/rendering/svg/RenderSVGText.h
+++ b/Source/WebCore/rendering/svg/RenderSVGText.h
@@ -26,6 +26,7 @@
#include "AffineTransform.h"
#include "RenderSVGBlock.h"
+#include "SVGTextLayoutAttributes.h"
namespace WebCore {
@@ -33,7 +34,7 @@ class SVGTextElement;
class RenderSVGText : public RenderSVGBlock {
public:
- RenderSVGText(SVGTextElement* node);
+ RenderSVGText(SVGTextElement*);
void setNeedsPositioningValuesUpdate() { m_needsPositioningValuesUpdate = true; }
virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; }
@@ -42,6 +43,9 @@ public:
static RenderSVGText* locateRenderSVGTextAncestor(RenderObject*);
static const RenderSVGText* locateRenderSVGTextAncestor(const RenderObject*);
+ Vector<SVGTextLayoutAttributes>& layoutAttributes() { return m_layoutAttributes; }
+ bool needsReordering() const { return m_needsReordering; }
+
private:
virtual const char* renderName() const { return "RenderSVGText"; }
virtual bool isSVGText() const { return true; }
@@ -71,9 +75,11 @@ private:
virtual RenderBlock* firstLineBlock() const;
virtual void updateFirstLetter();
+ bool m_needsReordering : 1;
bool m_needsPositioningValuesUpdate : 1;
bool m_needsTransformUpdate : 1;
AffineTransform m_localTransform;
+ Vector<SVGTextLayoutAttributes> m_layoutAttributes;
};
inline RenderSVGText* toRenderSVGText(RenderObject* object)
diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
index 05e1357..17bbfaa 100644
--- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
+++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp
@@ -73,7 +73,7 @@ int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragmen
if (!fragment.transform.isIdentity())
textRun.setHorizontalGlyphStretch(narrowPrecisionToFloat(fragment.transform.xScale()));
- return fragment.positionListOffset - start() + textRenderer->scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs);
+ return fragment.characterOffset - start() + textRenderer->scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs);
}
float SVGInlineTextBox::positionForOffset(int) const
@@ -402,7 +402,7 @@ TextRun SVGInlineTextBox::constructTextRun(RenderStyle* style, const SVGTextFrag
RenderText* text = textRenderer();
ASSERT(text);
- TextRun run(text->characters() + fragment.positionListOffset
+ TextRun run(text->characters() + fragment.characterOffset
, fragment.length
, false /* allowTabs */
, 0 /* xPos, only relevant with allowTabs=true */
@@ -425,7 +425,7 @@ bool SVGInlineTextBox::mapStartEndPositionsIntoFragmentCoordinates(const SVGText
if (startPosition >= endPosition)
return false;
- int offset = static_cast<int>(fragment.positionListOffset) - start();
+ int offset = static_cast<int>(fragment.characterOffset) - start();
int length = static_cast<int>(fragment.length);
if (startPosition >= offset + length || endPosition <= offset)
diff --git a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp
index 0f94fdd..a099f87 100644
--- a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp
+++ b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp
@@ -464,8 +464,8 @@ static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textB
SVGTextFragment& fragment = fragments.at(i);
writeIndent(ts, indent + 1);
- unsigned startOffset = fragment.positionListOffset;
- unsigned endOffset = fragment.positionListOffset + fragment.length;
+ unsigned startOffset = fragment.characterOffset;
+ unsigned endOffset = fragment.characterOffset + fragment.length;
// 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 ";
@@ -500,7 +500,7 @@ static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textB
ts << " override";
}
- ts << ": " << quoteAndEscapeNonPrintables(text.substring(fragment.positionListOffset, fragment.length)) << "\n";
+ ts << ": " << quoteAndEscapeNonPrintables(text.substring(fragment.characterOffset, fragment.length)) << "\n";
}
}
diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
index c2289d6..ddbd3ea 100644
--- a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
+++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp
@@ -25,8 +25,8 @@
#if ENABLE(SVG)
#include "GraphicsContext.h"
-#include "RenderBlock.h"
#include "RenderSVGInlineText.h"
+#include "RenderSVGText.h"
#include "SVGInlineFlowBox.h"
#include "SVGInlineTextBox.h"
#include "SVGNames.h"
@@ -73,8 +73,15 @@ void SVGRootInlineBox::paint(PaintInfo& paintInfo, int, int)
void SVGRootInlineBox::computePerCharacterLayoutInformation()
{
+ RenderSVGText* parentBlock = toRenderSVGText(block());
+ ASSERT(parentBlock);
+
+ Vector<SVGTextLayoutAttributes>& attributes = parentBlock->layoutAttributes();
+ if (parentBlock->needsReordering())
+ reorderValueLists(attributes);
+
// Perform SVG text layout phase two (see SVGTextLayoutEngine for details).
- SVGTextLayoutEngine characterLayout;
+ SVGTextLayoutEngine characterLayout(attributes);
layoutCharactersInTextBoxes(this, characterLayout);
// Perform SVG text layout phase three (see SVGTextChunkBuilder for details).
@@ -108,8 +115,12 @@ void SVGRootInlineBox::layoutCharactersInTextBoxes(InlineFlowBox* start, SVGText
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;
+ RenderSVGText* parentBlock = toRenderSVGText(block());
+ ASSERT(parentBlock);
+
+ SVGTextLayoutEngine lineLayout(parentBlock->layoutAttributes());
layoutCharactersInTextBoxes(flowBox, lineLayout);
+
characterLayout.beginTextPathLayout(child->renderer(), lineLayout);
}
@@ -215,6 +226,91 @@ InlineBox* SVGRootInlineBox::closestLeafChildForPosition(const IntPoint& point)
return closestLeaf ? closestLeaf : lastLeaf;
}
+
+static inline void swapItemsInVector(Vector<float>& firstVector, Vector<float>& lastVector, unsigned first, unsigned last)
+{
+ float temp = firstVector.at(first);
+ firstVector.at(first) = lastVector.at(last);
+ lastVector.at(last) = temp;
+}
+
+static inline void swapItemsInLayoutAttributes(SVGTextLayoutAttributes& firstAttributes, SVGTextLayoutAttributes& lastAttributes, unsigned firstPosition, unsigned lastPosition)
+{
+ swapItemsInVector(firstAttributes.xValues(), lastAttributes.xValues(), firstPosition, lastPosition);
+ swapItemsInVector(firstAttributes.yValues(), lastAttributes.yValues(), firstPosition, lastPosition);
+ swapItemsInVector(firstAttributes.dxValues(), lastAttributes.dxValues(), firstPosition, lastPosition);
+ swapItemsInVector(firstAttributes.dyValues(), lastAttributes.dyValues(), firstPosition, lastPosition);
+ swapItemsInVector(firstAttributes.rotateValues(), lastAttributes.rotateValues(), firstPosition, lastPosition);
+}
+
+static inline void findFirstAndLastAttributesInVector(Vector<SVGTextLayoutAttributes>& attributes, RenderSVGInlineText* firstContext, RenderSVGInlineText* lastContext,
+ SVGTextLayoutAttributes*& first, SVGTextLayoutAttributes*& last)
+{
+ first = 0;
+ last = 0;
+
+ unsigned attributesSize = attributes.size();
+ for (unsigned i = 0; i < attributesSize; ++i) {
+ SVGTextLayoutAttributes& current = attributes.at(i);
+ if (!first && firstContext == current.context())
+ first = &current;
+ if (!last && lastContext == current.context())
+ last = &current;
+ if (first && last)
+ break;
+ }
+
+ ASSERT(first);
+ ASSERT(last);
+}
+
+static inline void reverseInlineBoxRangeAndValueListsIfNeeded(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last)
+{
+ ASSERT(userData);
+ Vector<SVGTextLayoutAttributes>& attributes = *reinterpret_cast<Vector<SVGTextLayoutAttributes>*>(userData);
+
+ // This is a copy of std::reverse(first, last). It additionally assure that the value lists within the InlineBoxes are reordered as well.
+ while (true) {
+ if (first == last || first == --last)
+ return;
+
+ ASSERT((*first)->isSVGInlineTextBox());
+ ASSERT((*last)->isSVGInlineTextBox());
+
+ SVGInlineTextBox* firstTextBox = static_cast<SVGInlineTextBox*>(*first);
+ SVGInlineTextBox* lastTextBox = static_cast<SVGInlineTextBox*>(*last);
+
+ // Reordering is only necessary for BiDi text that is _absolutely_ positioned.
+ if (firstTextBox->len() == 1 && firstTextBox->len() == lastTextBox->len()) {
+ RenderSVGInlineText* firstContext = toRenderSVGInlineText(firstTextBox->textRenderer());
+ RenderSVGInlineText* lastContext = toRenderSVGInlineText(lastTextBox->textRenderer());
+
+ SVGTextLayoutAttributes* firstAttributes = 0;
+ SVGTextLayoutAttributes* lastAttributes = 0;
+ findFirstAndLastAttributesInVector(attributes, firstContext, lastContext, firstAttributes, lastAttributes);
+
+ unsigned firstBoxPosition = firstTextBox->start();
+ unsigned firstBoxEnd = firstTextBox->end();
+
+ unsigned lastBoxPosition = lastTextBox->start();
+ unsigned lastBoxEnd = lastTextBox->end();
+ for (; firstBoxPosition <= firstBoxEnd && lastBoxPosition <= lastBoxEnd; ++lastBoxPosition, ++firstBoxPosition)
+ swapItemsInLayoutAttributes(*firstAttributes, *lastAttributes, firstBoxPosition, lastBoxPosition);
+ }
+
+ InlineBox* temp = *first;
+ *first = *last;
+ *last = temp;
+
+ ++first;
+ }
+}
+
+void SVGRootInlineBox::reorderValueLists(Vector<SVGTextLayoutAttributes>& attributes)
+{
+ Vector<InlineBox*> leafBoxesInLogicalOrder;
+ collectLeafBoxesInLogicalOrder(leafBoxesInLogicalOrder, reverseInlineBoxRangeAndValueListsIfNeeded, &attributes);
+}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.h b/Source/WebCore/rendering/svg/SVGRootInlineBox.h
index 2e073c9..39612e7 100644
--- a/Source/WebCore/rendering/svg/SVGRootInlineBox.h
+++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.h
@@ -55,6 +55,7 @@ public:
InlineBox* closestLeafChildForPosition(const IntPoint&);
private:
+ void reorderValueLists(Vector<SVGTextLayoutAttributes>&);
void layoutCharactersInTextBoxes(InlineFlowBox*, SVGTextLayoutEngine&);
void layoutChildBoxes(InlineFlowBox*);
void layoutRootBox();
diff --git a/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp b/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp
index 2d84c48..9ccdef0 100644
--- a/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp
+++ b/Source/WebCore/rendering/svg/SVGShadowTreeElements.cpp
@@ -47,6 +47,10 @@ FloatSize SVGShadowTreeContainerElement::containerTranslation() const
return FloatSize(m_xOffset.value(this), m_yOffset.value(this));
}
+PassRefPtr<Element> SVGShadowTreeContainerElement::cloneElementWithoutAttributesAndChildren() const
+{
+ return adoptRef(new SVGShadowTreeContainerElement(document()));
+}
// SVGShadowTreeRootElement
inline SVGShadowTreeRootElement::SVGShadowTreeRootElement(Document* document, SVGUseElement* shadowParent)
diff --git a/Source/WebCore/rendering/svg/SVGShadowTreeElements.h b/Source/WebCore/rendering/svg/SVGShadowTreeElements.h
index 3406f95..2952e35 100644
--- a/Source/WebCore/rendering/svg/SVGShadowTreeElements.h
+++ b/Source/WebCore/rendering/svg/SVGShadowTreeElements.h
@@ -44,6 +44,7 @@ protected:
SVGShadowTreeContainerElement(Document*);
private:
+ virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren() const;
virtual bool isShadowTreeContainerElement() const { return true; }
SVGLength m_xOffset;
diff --git a/Source/WebCore/rendering/svg/SVGTextChunk.cpp b/Source/WebCore/rendering/svg/SVGTextChunk.cpp
index 5dea6ad..49407e5 100644
--- a/Source/WebCore/rendering/svg/SVGTextChunk.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextChunk.cpp
@@ -27,10 +27,8 @@
namespace WebCore {
-SVGTextChunk::SVGTextChunk(bool isVerticalText, ETextAnchor textAnchor, SVGTextContentElement::SVGLengthAdjustType lengthAdjust, float desiredTextLength)
- : m_isVerticalText(isVerticalText)
- , m_textAnchor(textAnchor)
- , m_lengthAdjust(lengthAdjust)
+SVGTextChunk::SVGTextChunk(unsigned chunkStyle, float desiredTextLength)
+ : m_chunkStyle(chunkStyle)
, m_desiredTextLength(desiredTextLength)
{
}
@@ -52,7 +50,7 @@ void SVGTextChunk::calculateLength(float& length, unsigned& characters) const
SVGTextFragment& fragment = fragments.at(i);
characters += fragment.length;
- if (m_isVerticalText)
+ if (m_chunkStyle & VerticalText)
length += fragment.height;
else
length += fragment.width;
@@ -63,7 +61,7 @@ void SVGTextChunk::calculateLength(float& length, unsigned& characters) const
}
// Resepect gap between chunks.
- if (m_isVerticalText)
+ if (m_chunkStyle & VerticalText)
length += fragment.y - (lastFragment->y + lastFragment->height);
else
length += fragment.x - (lastFragment->x + lastFragment->width);
@@ -75,17 +73,11 @@ void SVGTextChunk::calculateLength(float& length, unsigned& characters) const
float SVGTextChunk::calculateTextAnchorShift(float length) const
{
- switch (m_textAnchor) {
- case TA_START:
- return 0;
- case TA_MIDDLE:
+ if (m_chunkStyle & MiddleAnchor)
return -length / 2;
- case TA_END:
- return -length;
- };
-
- ASSERT_NOT_REACHED();
- return 0;
+ if (m_chunkStyle & EndAnchor)
+ return m_chunkStyle & RightToLeftText ? 0 : -length;
+ return m_chunkStyle & RightToLeftText ? -length : 0;
}
} // namespace WebCore
diff --git a/Source/WebCore/rendering/svg/SVGTextChunk.h b/Source/WebCore/rendering/svg/SVGTextChunk.h
index ebe6d81..9618d9f 100644
--- a/Source/WebCore/rendering/svg/SVGTextChunk.h
+++ b/Source/WebCore/rendering/svg/SVGTextChunk.h
@@ -31,34 +31,37 @@ 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);
+ enum ChunkStyle {
+ DefaultStyle = 1 << 0,
+ MiddleAnchor = 1 << 1,
+ EndAnchor = 1 << 2,
+ RightToLeftText = 1 << 3,
+ VerticalText = 1 << 4,
+ LengthAdjustSpacing = 1 << 5,
+ LengthAdjustSpacingAndGlyphs = 1 << 6
+ };
+
+ SVGTextChunk(unsigned chunkStyle, 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; }
+ bool isVerticalText() const { return m_chunkStyle & VerticalText; }
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; }
+ bool hasDesiredTextLength() const { return m_desiredTextLength > 0 && ((m_chunkStyle & LengthAdjustSpacing) || (m_chunkStyle & LengthAdjustSpacingAndGlyphs)); }
+ bool hasTextAnchor() const { return m_chunkStyle & RightToLeftText ? !(m_chunkStyle & EndAnchor) : (m_chunkStyle & MiddleAnchor) || (m_chunkStyle & EndAnchor); }
+ bool hasLengthAdjustSpacing() const { return m_chunkStyle & LengthAdjustSpacing; }
+ bool hasLengthAdjustSpacingAndGlyphs() const { return m_chunkStyle & LengthAdjustSpacingAndGlyphs; }
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;
+ unsigned m_chunkStyle;
float m_desiredTextLength;
};
diff --git a/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp b/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp
index bbbae6c..47311bd 100644
--- a/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp
@@ -101,15 +101,47 @@ void SVGTextChunkBuilder::addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxe
const SVGRenderStyle* svgStyle = style->svgStyle();
ASSERT(svgStyle);
- SVGTextContentElement::SVGLengthAdjustType lengthAdjust = SVGTextContentElement::LENGTHADJUST_UNKNOWN;
+ // Build chunk style flags.
+ unsigned chunkStyle = SVGTextChunk::DefaultStyle;
+
+ // Handle 'direction' property.
+ if (!style->isLeftToRightDirection())
+ chunkStyle |= SVGTextChunk::RightToLeftText;
+
+ // Handle 'writing-mode' property.
+ if (svgStyle->isVerticalWritingMode())
+ chunkStyle |= SVGTextChunk::VerticalText;
+
+ // Handle 'text-anchor' property.
+ switch (svgStyle->textAnchor()) {
+ case TA_START:
+ break;
+ case TA_MIDDLE:
+ chunkStyle |= SVGTextChunk::MiddleAnchor;
+ break;
+ case TA_END:
+ chunkStyle |= SVGTextChunk::EndAnchor;
+ break;
+ };
+
+ // Handle 'lengthAdjust' property.
float desiredTextLength = 0;
-
if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textRenderer->parent())) {
- lengthAdjust = static_cast<SVGTextContentElement::SVGLengthAdjustType>(textContentElement->lengthAdjust());
desiredTextLength = textContentElement->textLength().value(textContentElement);
+
+ switch (static_cast<SVGTextContentElement::SVGLengthAdjustType>(textContentElement->lengthAdjust())) {
+ case SVGTextContentElement::LENGTHADJUST_UNKNOWN:
+ break;
+ case SVGTextContentElement::LENGTHADJUST_SPACING:
+ chunkStyle |= SVGTextChunk::LengthAdjustSpacing;
+ break;
+ case SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS:
+ chunkStyle |= SVGTextChunk::LengthAdjustSpacingAndGlyphs;
+ break;
+ };
}
- SVGTextChunk chunk(svgStyle->isVerticalWritingMode(), svgStyle->textAnchor(), lengthAdjust, desiredTextLength);
+ SVGTextChunk chunk(chunkStyle, desiredTextLength);
Vector<SVGInlineTextBox*>& boxes = chunk.boxes();
for (unsigned i = boxStart; i < boxStart + boxCount; ++i)
@@ -137,7 +169,7 @@ void SVGTextChunkBuilder::processTextChunk(const SVGTextChunk& chunk)
bool isVerticalText = chunk.isVerticalText();
if (processTextLength) {
- if (chunk.lengthAdjust() == SVGTextContentElement::LENGTHADJUST_SPACING) {
+ if (chunk.hasLengthAdjustSpacing()) {
float textLengthShift = (chunk.desiredTextLength() - chunkLength) / chunkCharacters;
unsigned atCharacter = 0;
for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) {
@@ -147,7 +179,7 @@ void SVGTextChunkBuilder::processTextChunk(const SVGTextChunk& chunk)
processTextLengthSpacingCorrection(isVerticalText, textLengthShift, fragments, atCharacter);
}
} else {
- ASSERT(chunk.lengthAdjust() == SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS);
+ ASSERT(chunk.hasLengthAdjustSpacingAndGlyphs());
float scale = chunk.desiredTextLength() / chunkLength;
AffineTransform spacingAndGlyphsTransform;
@@ -172,7 +204,7 @@ void SVGTextChunkBuilder::processTextChunk(const SVGTextChunk& chunk)
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) {
+ if (processTextLength && chunk.hasLengthAdjustSpacing()) {
chunkLength = 0;
chunkCharacters = 0;
chunk.calculateLength(chunkLength, chunkCharacters);
diff --git a/Source/WebCore/rendering/svg/SVGTextFragment.h b/Source/WebCore/rendering/svg/SVGTextFragment.h
index 2e520da..b5b3c57 100644
--- a/Source/WebCore/rendering/svg/SVGTextFragment.h
+++ b/Source/WebCore/rendering/svg/SVGTextFragment.h
@@ -28,7 +28,8 @@ namespace WebCore {
// A SVGTextFragment describes a text fragment of a RenderSVGInlineText which can be rendered at once.
struct SVGTextFragment {
SVGTextFragment()
- : positionListOffset(0)
+ : characterOffset(0)
+ , metricsListOffset(0)
, length(0)
, x(0)
, y(0)
@@ -37,8 +38,9 @@ struct SVGTextFragment {
{
}
- // The first rendered character starts at RenderSVGInlineText::characters() + positionListOffset.
- unsigned positionListOffset;
+ // The first rendered character starts at RenderSVGInlineText::characters() + characterOffset.
+ unsigned characterOffset;
+ unsigned metricsListOffset;
unsigned length;
float x;
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp
index 3037b77..4c227b4 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp
@@ -27,7 +27,8 @@
namespace WebCore {
-SVGTextLayoutAttributes::SVGTextLayoutAttributes()
+SVGTextLayoutAttributes::SVGTextLayoutAttributes(RenderSVGInlineText* context)
+ : m_context(context)
{
}
@@ -65,6 +66,8 @@ static inline void dumpLayoutVector(const Vector<float>& values)
void SVGTextLayoutAttributes::dump() const
{
+ fprintf(stderr, "context: %p\n", m_context);
+
fprintf(stderr, "x values: ");
dumpLayoutVector(m_xValues);
fprintf(stderr, "\n");
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h
index d08d5b7..fc6bd10 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h
@@ -27,15 +27,19 @@
namespace WebCore {
+class RenderSVGInlineText;
+
class SVGTextLayoutAttributes {
public:
- SVGTextLayoutAttributes();
+ SVGTextLayoutAttributes(RenderSVGInlineText* context = 0);
void reserveCapacity(unsigned length);
void dump() const;
static float emptyValue();
+ RenderSVGInlineText* context() const { return m_context; }
+
Vector<float>& xValues() { return m_xValues; }
const Vector<float>& xValues() const { return m_xValues; }
@@ -55,6 +59,7 @@ public:
const Vector<SVGTextMetrics>& textMetricsValues() const { return m_textMetricsValues; }
private:
+ RenderSVGInlineText* m_context;
Vector<float> m_xValues;
Vector<float> m_yValues;
Vector<float> m_dxValues;
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp
index 3122912..86be424 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp
@@ -52,9 +52,11 @@ void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextSubtree(RenderS
buildOutermostLayoutScope(textRoot, atCharacter);
// Propagate layout attributes to each RenderSVGInlineText object.
+ Vector<SVGTextLayoutAttributes>& allAttributes = textRoot->layoutAttributes();
+ allAttributes.clear();
atCharacter = 0;
lastCharacter = '\0';
- propagateLayoutAttributes(textRoot, atCharacter, lastCharacter);
+ propagateLayoutAttributes(textRoot, allAttributes, atCharacter, lastCharacter);
}
static inline void extractFloatValuesFromSVGLengthList(SVGElement* lengthContext, const SVGLengthList& list, Vector<float>& floatValues, unsigned textContentLength)
@@ -186,7 +188,7 @@ void SVGTextLayoutAttributesBuilder::buildOutermostLayoutScope(RenderSVGText* te
m_scopes.prepend(scope);
}
-void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* start, unsigned& atCharacter, UChar& lastCharacter) const
+void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* start, Vector<SVGTextLayoutAttributes>& allAttributes, unsigned& atCharacter, UChar& lastCharacter) const
{
for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
if (child->isSVGInlineText()) {
@@ -195,16 +197,29 @@ void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* sta
unsigned textLength = text->textLength();
bool preserveWhiteSpace = shouldPreserveAllWhiteSpace(text->style());
- SVGTextLayoutAttributes attributes;
+ SVGTextLayoutAttributes attributes(text);
attributes.reserveCapacity(textLength);
unsigned valueListPosition = atCharacter;
unsigned metricsLength = 1;
+ SVGTextMetrics lastMetrics = SVGTextMetrics::emptyMetrics();
+
for (unsigned textPosition = 0; textPosition < textLength; textPosition += metricsLength) {
const UChar& currentCharacter = characters[textPosition];
- SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(text, textPosition, 1);
- metricsLength = metrics.length();
+ SVGTextMetrics startToCurrentMetrics = SVGTextMetrics::measureCharacterRange(text, 0, textPosition + 1);
+ SVGTextMetrics currentMetrics = SVGTextMetrics::measureCharacterRange(text, textPosition, 1);
+
+ // Frequent case for Arabic text: when measuring a single character the arabic isolated form is taken
+ // when rendering the glyph "in context" (with it's surrounding characters) it changes due to shaping.
+ // So whenever runWidthAdvance != currentMetrics.width(), we are processing a text run whose length is
+ // not equal to the sum of the individual lengths of the glyphs, when measuring them isolated.
+ float runWidthAdvance = startToCurrentMetrics.width() - lastMetrics.width();
+ if (runWidthAdvance != currentMetrics.width())
+ currentMetrics.setWidth(runWidthAdvance);
+
+ lastMetrics = startToCurrentMetrics;
+ metricsLength = currentMetrics.length();
if (!preserveWhiteSpace && characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter)) {
assignEmptyLayoutAttributesForCharacter(attributes);
@@ -212,7 +227,7 @@ void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* sta
continue;
}
- assignLayoutAttributesForCharacter(attributes, metrics, valueListPosition);
+ assignLayoutAttributesForCharacter(attributes, currentMetrics, valueListPosition);
if (metricsLength > 1) {
for (unsigned i = 0; i < metricsLength - 1; ++i)
@@ -225,10 +240,12 @@ void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* sta
#if DUMP_TEXT_LAYOUT_ATTRIBUTES > 0
fprintf(stderr, "\nDumping layout attributes for RenderSVGInlineText, renderer=%p, node=%p (atCharacter: %i)\n", text, text->node(), atCharacter);
+ fprintf(stderr, "BiDi properties: unicode-bidi=%i, block direction=%i\n", text->style()->unicodeBidi(), text->style()->direction());
attributes.dump();
#endif
text->storeLayoutAttributes(attributes);
+ allAttributes.append(attributes);
atCharacter = valueListPosition;
continue;
}
@@ -236,7 +253,7 @@ void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* sta
if (!child->isSVGInline())
continue;
- propagateLayoutAttributes(child, atCharacter, lastCharacter);
+ propagateLayoutAttributes(child, allAttributes, atCharacter, lastCharacter);
}
}
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h
index c68185b..b368c51 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h
@@ -60,7 +60,7 @@ private:
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;
+ void propagateLayoutAttributes(RenderObject*, Vector<SVGTextLayoutAttributes>& allAttributes, unsigned& atCharacter, UChar& lastCharacter) const;
enum LayoutValueType {
XValueAttribute,
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp
index c25ed79..71db2ea 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp
@@ -34,8 +34,13 @@
namespace WebCore {
-SVGTextLayoutEngine::SVGTextLayoutEngine()
- : m_x(0)
+SVGTextLayoutEngine::SVGTextLayoutEngine(Vector<SVGTextLayoutAttributes>& layoutAttributes)
+ : m_layoutAttributes(layoutAttributes)
+ , m_logicalCharacterOffset(0)
+ , m_logicalMetricsListOffset(0)
+ , m_visualCharacterOffset(0)
+ , m_visualMetricsListOffset(0)
+ , m_x(0)
, m_y(0)
, m_dx(0)
, m_dy(0)
@@ -46,6 +51,7 @@ SVGTextLayoutEngine::SVGTextLayoutEngine()
, m_textPathSpacing(0)
, m_textPathScaling(1)
{
+ ASSERT(!m_layoutAttributes.isEmpty());
}
void SVGTextLayoutEngine::updateCharacerPositionIfNeeded(float& x, float& y)
@@ -77,7 +83,7 @@ void SVGTextLayoutEngine::updateCurrentTextPosition(float x, float y, float glyp
}
}
-void SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded(Vector<float>& dxValues, Vector<float>& dyValues, unsigned positionListOffset)
+void SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded(Vector<float>& dxValues, Vector<float>& dyValues)
{
// Update relative positioning information.
if (dxValues.isEmpty() && dyValues.isEmpty())
@@ -85,14 +91,14 @@ void SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded(Vector<float
float dx = 0;
if (!dxValues.isEmpty()) {
- float& dxCurrent = dxValues.at(positionListOffset);
+ float& dxCurrent = dxValues.at(m_logicalCharacterOffset);
if (dxCurrent != SVGTextLayoutAttributes::emptyValue())
dx = dxCurrent;
}
float dy = 0;
if (!dyValues.isEmpty()) {
- float& dyCurrent = dyValues.at(positionListOffset);
+ float& dyCurrent = dyValues.at(m_logicalCharacterOffset);
if (dyCurrent != SVGTextLayoutAttributes::emptyValue())
dy = dyCurrent;
}
@@ -113,23 +119,31 @@ void SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded(Vector<float
m_dy = dy;
}
-void SVGTextLayoutEngine::recordTextFragment(SVGInlineTextBox* textBox, RenderSVGInlineText* text, unsigned positionListOffset, const SVGTextMetrics& lastCharacterMetrics)
+void SVGTextLayoutEngine::recordTextFragment(SVGInlineTextBox* textBox, Vector<SVGTextMetrics>& textMetricsValues)
{
ASSERT(!m_currentTextFragment.length);
+ ASSERT(m_visualMetricsListOffset > 0);
// Figure out length of fragment.
- m_currentTextFragment.length = positionListOffset - m_currentTextFragment.positionListOffset;
+ m_currentTextFragment.length = m_visualCharacterOffset - m_currentTextFragment.characterOffset;
// 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();
+ SVGTextMetrics& lastCharacterMetrics = textMetricsValues.at(m_visualMetricsListOffset - 1);
+ m_currentTextFragment.width = lastCharacterMetrics.width();
+ m_currentTextFragment.height = lastCharacterMetrics.height();
+
+ if (m_currentTextFragment.length > 1) {
+ // SVGTextLayoutAttributesBuilder assures that the length of the range is equal to the sum of the individual lengths of the glyphs.
+ float length = 0;
+ if (m_isVerticalText) {
+ for (unsigned i = m_currentTextFragment.metricsListOffset; i < m_visualMetricsListOffset; ++i)
+ length += textMetricsValues.at(i).height();
+ m_currentTextFragment.height = length;
+ } else {
+ for (unsigned i = m_currentTextFragment.metricsListOffset; i < m_visualMetricsListOffset; ++i)
+ length += textMetricsValues.at(i).width();
+ m_currentTextFragment.width = length;
+ }
}
textBox->textFragments().append(m_currentTextFragment);
@@ -281,7 +295,7 @@ void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& b
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, " textBox properties, start=%i, len=%i, box direction=%i\n", textBox->start(), textBox->len(), textBox->direction());
fprintf(stderr, " textRenderer properties, textLength=%i\n", textBox->textRenderer()->textLength());
const UChar* characters = textBox->textRenderer()->characters();
@@ -289,9 +303,9 @@ void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& b
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());
+ String fragmentString(characters + fragment.characterOffset, fragment.length);
+ fprintf(stderr, " -> Fragment %i, x=%lf, y=%lf, width=%lf, height=%lf, characterOffset=%i, length=%i, characters='%s'\n"
+ , i, fragment.x, fragment.y, fragment.width, fragment.height, fragment.characterOffset, fragment.length, fragmentString.utf8().data());
}
}
#endif
@@ -328,6 +342,97 @@ void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& b
boxes.clear();
}
+bool SVGTextLayoutEngine::currentLogicalCharacterAttributes(SVGTextLayoutAttributes& logicalAttributes)
+{
+ logicalAttributes = m_layoutAttributes.first();
+ if (m_logicalCharacterOffset != logicalAttributes.xValues().size())
+ return true;
+
+ m_layoutAttributes.remove(0);
+ if (m_layoutAttributes.isEmpty())
+ return false;
+
+ logicalAttributes = m_layoutAttributes.first();
+ m_logicalMetricsListOffset = 0;
+ m_logicalCharacterOffset = 0;
+ return true;
+}
+
+bool SVGTextLayoutEngine::currentLogicalCharacterMetrics(SVGTextLayoutAttributes& logicalAttributes, SVGTextMetrics& logicalMetrics)
+{
+ logicalMetrics = SVGTextMetrics::emptyMetrics();
+
+ Vector<SVGTextMetrics>& textMetricsValues = logicalAttributes.textMetricsValues();
+ unsigned textMetricsSize = textMetricsValues.size();
+ while (true) {
+ if (m_logicalMetricsListOffset == textMetricsSize) {
+ if (!currentLogicalCharacterAttributes(logicalAttributes))
+ return false;
+
+ textMetricsValues = logicalAttributes.textMetricsValues();
+ textMetricsSize = textMetricsValues.size();
+ continue;
+ }
+
+ logicalMetrics = textMetricsValues.at(m_logicalMetricsListOffset);
+ if (logicalMetrics == SVGTextMetrics::emptyMetrics() || (!logicalMetrics.width() && !logicalMetrics.height())) {
+ advanceToNextLogicalCharacter(logicalMetrics);
+ continue;
+ }
+
+ // Stop if we found the next valid logical text metrics object.
+ return true;
+ }
+
+ ASSERT_NOT_REACHED();
+ return true;
+}
+
+bool SVGTextLayoutEngine::currentVisualCharacterMetrics(SVGInlineTextBox* textBox, RenderSVGInlineText* text, SVGTextMetrics& metrics)
+{
+ SVGTextLayoutAttributes& attributes = text->layoutAttributes();
+ Vector<SVGTextMetrics>& textMetricsValues = attributes.textMetricsValues();
+ ASSERT(!textMetricsValues.isEmpty());
+
+ unsigned textMetricsSize = textMetricsValues.size();
+ unsigned boxStart = textBox->start();
+ unsigned boxLength = textBox->len();
+
+ if (m_visualMetricsListOffset == textMetricsSize)
+ return false;
+
+ while (m_visualMetricsListOffset < textMetricsSize) {
+ SVGTextMetrics& visualMetrics = textMetricsValues.at(m_visualMetricsListOffset);
+
+ // Advance to text box start location.
+ if (m_visualCharacterOffset < boxStart) {
+ advanceToNextVisualCharacter(visualMetrics);
+ continue;
+ }
+
+ // Stop if we've finished processing this text box.
+ if (m_visualCharacterOffset >= boxStart + boxLength)
+ return false;
+
+ metrics = visualMetrics;
+ return true;
+ }
+
+ return false;
+}
+
+void SVGTextLayoutEngine::advanceToNextLogicalCharacter(const SVGTextMetrics& logicalMetrics)
+{
+ ++m_logicalMetricsListOffset;
+ m_logicalCharacterOffset += logicalMetrics.length();
+}
+
+void SVGTextLayoutEngine::advanceToNextVisualCharacter(const SVGTextMetrics& visualMetrics)
+{
+ ++m_visualMetricsListOffset;
+ m_visualCharacterOffset += visualMetrics.length();
+}
+
void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, RenderSVGInlineText* text, const RenderStyle* style)
{
SVGElement* lengthContext = static_cast<SVGElement*>(text->parent()->node());
@@ -338,26 +443,10 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend
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());
+ m_visualMetricsListOffset = 0;
+ m_visualCharacterOffset = 0;
- if (boxLength > textMetricsSize)
- textMetricsSize = boxLength;
-
- unsigned positionListOffset = 0;
- unsigned metricsListOffset = 0;
+ Vector<SVGTextMetrics>& textMetricsValues = text->layoutAttributes().textMetricsValues();
const UChar* characters = text->characters();
const Font& font = style->font();
@@ -372,56 +461,63 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend
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();
+ while (true) {
+ // Find the start of the current text box in this list, respecting ligatures.
+ SVGTextMetrics visualMetrics = SVGTextMetrics::emptyMetrics();
+ if (!currentVisualCharacterMetrics(textBox, text, visualMetrics))
+ break;
+
+ if (visualMetrics == SVGTextMetrics::emptyMetrics()) {
+ advanceToNextVisualCharacter(visualMetrics);
continue;
}
- // Stop if we've finished processing this text box.
- if (positionListOffset >= boxStart + boxLength)
+ SVGTextLayoutAttributes logicalAttributes;
+ if (!currentLogicalCharacterAttributes(logicalAttributes))
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));
+ SVGTextMetrics logicalMetrics = SVGTextMetrics::emptyMetrics();
+ if (!currentLogicalCharacterMetrics(logicalAttributes, logicalMetrics))
+ break;
- if (metrics == SVGTextMetrics::emptyMetrics()) {
- positionListOffset += metrics.length();
- continue;
- }
+ Vector<float>& xValues = logicalAttributes.xValues();
+ Vector<float>& yValues = logicalAttributes.yValues();
+ Vector<float>& dxValues = logicalAttributes.dxValues();
+ Vector<float>& dyValues = logicalAttributes.dyValues();
+ Vector<float>& rotateValues = logicalAttributes.rotateValues();
+
+ float x = xValues.at(m_logicalCharacterOffset);
+ float y = yValues.at(m_logicalCharacterOffset);
+
+ // When we've advanced to the box start offset, determine using the original x/y values,
+ // whether this character starts a new text chunk, before doing any further processing.
+ if (m_visualCharacterOffset == textBox->start())
+ textBox->setStartsNewTextChunk(logicalAttributes.context()->characterStartsNewTextChunk(m_logicalCharacterOffset));
- const UChar* currentCharacter = characters + positionListOffset;
float angle = 0;
if (!rotateValues.isEmpty()) {
- float newAngle = rotateValues.at(positionListOffset);
+ float newAngle = rotateValues.at(m_logicalCharacterOffset);
if (newAngle != SVGTextLayoutAttributes::emptyValue())
angle = newAngle;
}
// Calculate glyph orientation angle.
+ const UChar* currentCharacter = characters + m_visualCharacterOffset;
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);
+ float glyphAdvance = baselineLayout.calculateGlyphAdvanceAndOrientation(m_isVerticalText, visualMetrics, 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);
+ updateRelativePositionAdjustmentsIfNeeded(dxValues, dyValues);
// Calculate SVG Fonts kerning, if needed.
- float kerning = spacingLayout.calculateSVGKerning(m_isVerticalText, metrics.glyph());
+ float kerning = spacingLayout.calculateSVGKerning(m_isVerticalText, visualMetrics.glyph());
// Calculate CSS 'kerning', 'letter-spacing' and 'word-spacing' for next character, if needed.
float spacing = spacingLayout.calculateCSSKerningAndSpacing(svgStyle, lengthContext, currentCharacter);
@@ -461,7 +557,8 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend
// Skip character, if we're before the path.
if (textPathOffset < 0) {
- positionListOffset += metrics.length();
+ advanceToNextLogicalCharacter(logicalMetrics);
+ advanceToNextVisualCharacter(visualMetrics);
continue;
}
@@ -513,16 +610,17 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend
// If we already started a fragment, close it now.
if (didStartTextFragment && shouldStartNewFragment) {
applySpacingToNextCharacter = false;
- recordTextFragment(textBox, text, positionListOffset, textMetricsValues.at(metricsListOffset - 1));
+ recordTextFragment(textBox, textMetricsValues);
}
// Eventually start a new fragment, if not yet done.
if (!didStartTextFragment || shouldStartNewFragment) {
- ASSERT(!m_currentTextFragment.positionListOffset);
+ ASSERT(!m_currentTextFragment.characterOffset);
ASSERT(!m_currentTextFragment.length);
didStartTextFragment = true;
- m_currentTextFragment.positionListOffset = positionListOffset;
+ m_currentTextFragment.characterOffset = m_visualCharacterOffset;
+ m_currentTextFragment.metricsListOffset = m_visualMetricsListOffset;
m_currentTextFragment.x = x;
m_currentTextFragment.y = y;
@@ -563,7 +661,8 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend
updateCurrentTextPosition(xNew, yNew, glyphAdvance + spacing);
}
- positionListOffset += metrics.length();
+ advanceToNextLogicalCharacter(logicalMetrics);
+ advanceToNextVisualCharacter(visualMetrics);
lastAngle = angle;
}
@@ -571,7 +670,7 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend
return;
// Close last open fragment, if needed.
- recordTextFragment(textBox, text, positionListOffset, textMetricsValues.at(metricsListOffset - 1));
+ recordTextFragment(textBox, textMetricsValues);
}
}
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.h b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.h
index 631e4cd..22dd59b 100644
--- a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.h
+++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.h
@@ -24,6 +24,7 @@
#include "Path.h"
#include "SVGTextChunkBuilder.h"
#include "SVGTextFragment.h"
+#include "SVGTextLayoutAttributes.h"
#include "SVGTextMetrics.h"
#include <wtf/Vector.h>
@@ -47,7 +48,7 @@ class SVGRenderStyle;
class SVGTextLayoutEngine {
WTF_MAKE_NONCOPYABLE(SVGTextLayoutEngine);
public:
- SVGTextLayoutEngine();
+ SVGTextLayoutEngine(Vector<SVGTextLayoutAttributes>&);
SVGTextChunkBuilder& chunkLayoutBuilder() { return m_chunkLayoutBuilder; }
void beginTextPathLayout(RenderObject*, SVGTextLayoutEngine& lineLayout);
@@ -59,20 +60,32 @@ public:
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 updateRelativePositionAdjustmentsIfNeeded(Vector<float>& dxValues, Vector<float>& dyValues);
- void recordTextFragment(SVGInlineTextBox*, RenderSVGInlineText*, unsigned positionListOffset, const SVGTextMetrics& lastCharacterMetrics);
+ void recordTextFragment(SVGInlineTextBox*, Vector<SVGTextMetrics>& textMetricValues);
bool parentDefinesTextLength(RenderObject*) const;
void layoutTextOnLineOrPath(SVGInlineTextBox*, RenderSVGInlineText*, const RenderStyle*);
void finalizeTransformMatrices(Vector<SVGInlineTextBox*>&);
+ bool currentLogicalCharacterAttributes(SVGTextLayoutAttributes&);
+ bool currentLogicalCharacterMetrics(SVGTextLayoutAttributes&, SVGTextMetrics&);
+ bool currentVisualCharacterMetrics(SVGInlineTextBox*, RenderSVGInlineText*, SVGTextMetrics&);
+
+ void advanceToNextLogicalCharacter(const SVGTextMetrics&);
+ void advanceToNextVisualCharacter(const SVGTextMetrics&);
+
private:
+ Vector<SVGTextLayoutAttributes> m_layoutAttributes;
Vector<SVGInlineTextBox*> m_lineLayoutBoxes;
Vector<SVGInlineTextBox*> m_pathLayoutBoxes;
SVGTextChunkBuilder m_chunkLayoutBuilder;
SVGTextFragment m_currentTextFragment;
+ unsigned m_logicalCharacterOffset;
+ unsigned m_logicalMetricsListOffset;
+ unsigned m_visualCharacterOffset;
+ unsigned m_visualMetricsListOffset;
float m_x;
float m_y;
float m_dx;
diff --git a/Source/WebCore/rendering/svg/SVGTextMetrics.cpp b/Source/WebCore/rendering/svg/SVGTextMetrics.cpp
index d75bdb3..042bc22 100644
--- a/Source/WebCore/rendering/svg/SVGTextMetrics.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextMetrics.cpp
@@ -74,7 +74,17 @@ SVGTextMetrics SVGTextMetrics::emptyMetrics()
static TextRun constructTextRun(RenderSVGInlineText* text, const UChar* characters, unsigned position, unsigned length)
{
- TextRun run(characters + position, length);
+ RenderStyle* style = text->style();
+ ASSERT(style);
+
+ TextRun run(characters + position
+ , length
+ , false /* allowTabs */
+ , 0 /* xPos, only relevant with allowTabs=true */
+ , 0 /* padding, only relevant for justified text, not relevant for SVG */
+ , TextRun::AllowTrailingExpansion
+ , !style->isLeftToRightDirection()
+ , style->unicodeBidi() == Override /* directionalOverride */);
#if ENABLE(SVG_FONTS)
run.setReferencingRenderObject(text);
@@ -92,22 +102,6 @@ SVGTextMetrics SVGTextMetrics::measureCharacterRange(RenderSVGInlineText* text,
return SVGTextMetrics(text, run, position, text->textLength());
}
-void SVGTextMetrics::measureAllCharactersIndividually(RenderSVGInlineText* text, Vector<SVGTextMetrics>& allMetrics)
-{
- ASSERT(text);
- 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(text, run, position, text->textLength());
- allMetrics.append(metrics);
- position += metrics.length();
- }
-}
-
}
#endif // ENABLE(SVG)
diff --git a/Source/WebCore/rendering/svg/SVGTextMetrics.h b/Source/WebCore/rendering/svg/SVGTextMetrics.h
index 7ef0f7d..cb016b6 100644
--- a/Source/WebCore/rendering/svg/SVGTextMetrics.h
+++ b/Source/WebCore/rendering/svg/SVGTextMetrics.h
@@ -32,7 +32,6 @@ class SVGTextMetrics {
public:
static SVGTextMetrics emptyMetrics();
static SVGTextMetrics measureCharacterRange(RenderSVGInlineText*, unsigned position, unsigned length);
- static void measureAllCharactersIndividually(RenderSVGInlineText*, Vector<SVGTextMetrics>&);
bool operator==(const SVGTextMetrics&);
@@ -62,6 +61,10 @@ public:
const Glyph& glyph() const { return m_glyph; }
private:
+ friend class SVGTextLayoutAttributesBuilder;
+ void setWidth(float width) { m_width = width; }
+
+private:
SVGTextMetrics();
SVGTextMetrics(RenderSVGInlineText*, const TextRun&, unsigned position, unsigned textLength);
diff --git a/Source/WebCore/rendering/svg/SVGTextQuery.cpp b/Source/WebCore/rendering/svg/SVGTextQuery.cpp
index 1a4cdab..5f3523e 100644
--- a/Source/WebCore/rendering/svg/SVGTextQuery.cpp
+++ b/Source/WebCore/rendering/svg/SVGTextQuery.cpp
@@ -313,7 +313,7 @@ bool SVGTextQuery::subStringLengthCallback(Data* queryData, const SVGTextFragmen
if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition))
return false;
- SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.positionListOffset + startPosition, endPosition - startPosition);
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, endPosition - startPosition);
float fragmentLength = queryData->isVerticalText ? metrics.height() : metrics.width();
data->subStringLength += mapLengthThroughFragmentTransformation(fragment, queryData->isVerticalText, fragmentLength);
@@ -353,7 +353,7 @@ bool SVGTextQuery::startPositionOfCharacterCallback(Data* queryData, const SVGTe
data->startPosition = FloatPoint(fragment.x, fragment.y);
if (startPosition) {
- SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.positionListOffset, startPosition);
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition);
if (queryData->isVerticalText)
data->startPosition.move(0, metrics.height());
else
@@ -399,7 +399,7 @@ bool SVGTextQuery::endPositionOfCharacterCallback(Data* queryData, const SVGText
data->endPosition = FloatPoint(fragment.x, fragment.y);
- SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.positionListOffset, startPosition + 1);
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition + 1);
if (queryData->isVerticalText)
data->endPosition.move(0, metrics.height());
else
@@ -478,14 +478,14 @@ static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const
extent.setLocation(FloatPoint(fragment.x, fragment.y - queryData->textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor));
if (startPosition) {
- SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.positionListOffset, startPosition);
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, 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);
+ SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, 1);
extent.setSize(FloatSize(metrics.width(), metrics.height()));
if (fragment.transform.isIdentity())