summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/webkit/WebCore/editing/TextIterator.cpp
diff options
context:
space:
mode:
authorMichael Brasser <michael.brasser@nokia.com>2009-07-10 01:17:51 (GMT)
committerMichael Brasser <michael.brasser@nokia.com>2009-07-10 01:17:51 (GMT)
commit9c13caa3c99af01a9b4c3ff6e178e7dadb61741f (patch)
treeb69df0a23c4628359fc3740e09958980eda7478e /src/3rdparty/webkit/WebCore/editing/TextIterator.cpp
parentbb1bdcab28e4c52dcea37dfaaa435045b1985eeb (diff)
parent883da42f7c75775502c818aa456c8576d8457ff8 (diff)
downloadQt-9c13caa3c99af01a9b4c3ff6e178e7dadb61741f.zip
Qt-9c13caa3c99af01a9b4c3ff6e178e7dadb61741f.tar.gz
Qt-9c13caa3c99af01a9b4c3ff6e178e7dadb61741f.tar.bz2
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui-gv
Conflicts: examples/itemviews/frozencolumn/main.cpp src/declarative/canvas/qsimplecanvas.cpp src/declarative/canvas/qsimplecanvas_p.h src/declarative/canvas/qsimplecanvasitem.h src/declarative/extra/qfxparticles.cpp src/declarative/fx/fx.pri src/declarative/fx/qfxblurfilter.h src/declarative/fx/qfxcontentwrapper.cpp src/declarative/fx/qfxflickable.cpp src/declarative/fx/qfxfocuspanel.h src/declarative/fx/qfxfocusrealm.h src/declarative/fx/qfxhighlightfilter.cpp src/declarative/fx/qfxhighlightfilter.h src/declarative/fx/qfximage.cpp src/declarative/fx/qfxitem.cpp src/declarative/fx/qfxitem.h src/declarative/fx/qfxrect.cpp src/declarative/fx/qfxreflectionfilter.h src/declarative/fx/qfxshadowfilter.cpp src/declarative/fx/qfxshadowfilter.h src/declarative/fx/qfxtext.cpp src/declarative/fx/qfxtext.h src/declarative/fx/qfxtextedit.cpp src/declarative/opengl/glbasicshaders.h src/declarative/test/qfxtestengine.cpp src/declarative/test/qfxtestengine.h src/declarative/test/qfxtestobjects.cpp src/declarative/test/qfxtestobjects.h src/declarative/test/qfxtestview.h src/declarative/util/qfxglobal.h src/declarative/util/qfxview.cpp src/gui/graphicsview/qgraphicsitem_p.h tools/qmlviewer/qmlviewer.cpp
Diffstat (limited to 'src/3rdparty/webkit/WebCore/editing/TextIterator.cpp')
-rw-r--r--src/3rdparty/webkit/WebCore/editing/TextIterator.cpp211
1 files changed, 164 insertions, 47 deletions
diff --git a/src/3rdparty/webkit/WebCore/editing/TextIterator.cpp b/src/3rdparty/webkit/WebCore/editing/TextIterator.cpp
index b311853..aee34df 100644
--- a/src/3rdparty/webkit/WebCore/editing/TextIterator.cpp
+++ b/src/3rdparty/webkit/WebCore/editing/TextIterator.cpp
@@ -97,6 +97,118 @@ private:
// --------
+static const unsigned bitsInWord = sizeof(unsigned) * 8;
+static const unsigned bitInWordMask = bitsInWord - 1;
+
+BitStack::BitStack()
+ : m_size(0)
+{
+}
+
+void BitStack::push(bool bit)
+{
+ unsigned index = m_size / bitsInWord;
+ unsigned shift = m_size & bitInWordMask;
+ if (!shift && index == m_words.size()) {
+ m_words.grow(index + 1);
+ m_words[index] = 0;
+ }
+ unsigned& word = m_words[index];
+ unsigned mask = 1U << shift;
+ if (bit)
+ word |= mask;
+ else
+ word &= ~mask;
+ ++m_size;
+}
+
+void BitStack::pop()
+{
+ if (m_size)
+ --m_size;
+}
+
+bool BitStack::top() const
+{
+ if (!m_size)
+ return false;
+ unsigned shift = (m_size - 1) & bitInWordMask;
+ return m_words.last() & (1U << shift);
+}
+
+unsigned BitStack::size() const
+{
+ return m_size;
+}
+
+// --------
+
+static inline Node* parentOrShadowParent(Node* node)
+{
+ if (Node* parent = node->parentNode())
+ return parent;
+ return node->shadowParentNode();
+}
+
+#ifndef NDEBUG
+
+static unsigned depthCrossingShadowBoundaries(Node* node)
+{
+ unsigned depth = 0;
+ for (Node* parent = parentOrShadowParent(node); parent; parent = parentOrShadowParent(parent))
+ ++depth;
+ return depth;
+}
+
+#endif
+
+static inline bool fullyClipsContents(Node* node)
+{
+ RenderObject* renderer = node->renderer();
+ if (!renderer || !renderer->isBox())
+ return false;
+ RenderStyle* style = renderer->style();
+ if (style->overflowX() == OVISIBLE && style->overflowY() == OVISIBLE)
+ return false;
+ return toRenderBox(renderer)->size().isEmpty();
+}
+
+static inline bool ignoresContainerClip(Node* node)
+{
+ RenderObject* renderer = node->renderer();
+ if (!renderer || renderer->isText())
+ return false;
+ EPosition position = renderer->style()->position();
+ return position == AbsolutePosition || position == FixedPosition;
+}
+
+static void pushFullyClippedState(BitStack& stack, Node* node)
+{
+ ASSERT(stack.size() == depthCrossingShadowBoundaries(node));
+
+ // Push true if this node full clips its contents, or if a parent already has fully
+ // clipped and this is not a node that ignores its container's clip.
+ stack.push(fullyClipsContents(node) || stack.top() && !ignoresContainerClip(node));
+}
+
+static void setUpFullyClippedStack(BitStack& stack, Node* node)
+{
+ // Put the nodes in a vector so we can iterate in reverse order.
+ Vector<Node*, 100> ancestry;
+ for (Node* parent = parentOrShadowParent(node); parent; parent = parentOrShadowParent(parent))
+ ancestry.append(parent);
+
+ // Call pushFullyClippedState on each node starting with the earliest ancestor.
+ size_t size = ancestry.size();
+ for (size_t i = 0; i < size; ++i)
+ pushFullyClippedState(stack, ancestry[size - i - 1]);
+ pushFullyClippedState(stack, node);
+
+ ASSERT(stack.size() == 1 + depthCrossingShadowBoundaries(node));
+}
+
+// --------
+
TextIterator::TextIterator()
: m_startContainer(0)
, m_startOffset(0)
@@ -112,8 +224,7 @@ TextIterator::TextIterator()
}
TextIterator::TextIterator(const Range* r, bool emitCharactersBetweenAllVisiblePositions, bool enterTextControls)
- : m_inShadowContent(false)
- , m_startContainer(0)
+ : m_startContainer(0)
, m_startOffset(0)
, m_endContainer(0)
, m_endOffset(0)
@@ -144,17 +255,11 @@ TextIterator::TextIterator(const Range* r, bool emitCharactersBetweenAllVisibleP
m_endContainer = endContainer;
m_endOffset = endOffset;
- for (Node* n = startContainer; n; n = n->parentNode()) {
- if (n->isShadowNode()) {
- m_inShadowContent = true;
- break;
- }
- }
-
// set up the current node for processing
m_node = r->firstNode();
- if (m_node == 0)
+ if (!m_node)
return;
+ setUpFullyClippedStack(m_fullyClippedStack, m_node);
m_offset = m_node == m_startContainer ? m_startOffset : 0;
m_handledNode = false;
m_handledChildren = false;
@@ -219,7 +324,7 @@ void TextIterator::advance()
return;
}
- RenderObject *renderer = m_node->renderer();
+ RenderObject* renderer = m_node->renderer();
if (!renderer) {
m_handledNode = true;
m_handledChildren = true;
@@ -241,27 +346,20 @@ void TextIterator::advance()
// find a new current node to handle in depth-first manner,
// calling exitNode() as we come back thru a parent node
- Node *next = m_handledChildren ? 0 : m_node->firstChild();
+ Node* next = m_handledChildren ? 0 : m_node->firstChild();
m_offset = 0;
if (!next) {
next = m_node->nextSibling();
if (!next) {
bool pastEnd = m_node->traverseNextNode() == m_pastEndNode;
- Node* parentNode = m_node->parentNode();
- if (!parentNode && m_inShadowContent) {
- m_inShadowContent = false;
- parentNode = m_node->shadowParentNode();
- }
+ Node* parentNode = parentOrShadowParent(m_node);
while (!next && parentNode) {
if ((pastEnd && parentNode == m_endContainer) || m_endContainer->isDescendantOf(parentNode))
return;
bool haveRenderer = m_node->renderer();
m_node = parentNode;
- parentNode = m_node->parentNode();
- if (!parentNode && m_inShadowContent) {
- m_inShadowContent = false;
- parentNode = m_node->shadowParentNode();
- }
+ m_fullyClippedStack.pop();
+ parentNode = parentOrShadowParent(m_node);
if (haveRenderer)
exitNode();
if (m_positionNode) {
@@ -272,10 +370,13 @@ void TextIterator::advance()
next = m_node->nextSibling();
}
}
+ m_fullyClippedStack.pop();
}
// set the new current node
m_node = next;
+ if (m_node)
+ pushFullyClippedState(m_fullyClippedStack, m_node);
m_handledNode = false;
m_handledChildren = false;
@@ -285,13 +386,16 @@ void TextIterator::advance()
}
}
-static inline bool compareBoxStart(const InlineTextBox *first, const InlineTextBox *second)
+static inline bool compareBoxStart(const InlineTextBox* first, const InlineTextBox* second)
{
return first->start() < second->start();
}
bool TextIterator::handleTextNode()
{
+ if (m_fullyClippedStack.top())
+ return false;
+
RenderText* renderer = toRenderText(m_node->renderer());
if (renderer->style()->visibility() != VISIBLE)
return false;
@@ -325,7 +429,7 @@ bool TextIterator::handleTextNode()
// Used when text boxes are out of order (Hebrew/Arabic w/ embeded LTR text)
if (renderer->containsReversedText()) {
m_sortedTextBoxes.clear();
- for (InlineTextBox * textBox = renderer->firstTextBox(); textBox; textBox = textBox->nextTextBox()) {
+ for (InlineTextBox* textBox = renderer->firstTextBox(); textBox; textBox = textBox->nextTextBox()) {
m_sortedTextBoxes.append(textBox);
}
std::sort(m_sortedTextBoxes.begin(), m_sortedTextBoxes.end(), compareBoxStart);
@@ -339,7 +443,7 @@ bool TextIterator::handleTextNode()
void TextIterator::handleTextBox()
{
- RenderText *renderer = toRenderText(m_node->renderer());
+ RenderText* renderer = toRenderText(m_node->renderer());
String str = renderer->text();
int start = m_offset;
int end = (m_node == m_endContainer) ? m_endOffset : INT_MAX;
@@ -348,7 +452,7 @@ void TextIterator::handleTextBox()
int runStart = max(textBoxStart, start);
// Check for collapsed space at the start of this run.
- InlineTextBox *firstTextBox = renderer->containsReversedText() ? m_sortedTextBoxes[0] : renderer->firstTextBox();
+ InlineTextBox* firstTextBox = renderer->containsReversedText() ? m_sortedTextBoxes[0] : renderer->firstTextBox();
bool needSpace = m_lastTextNodeEndedWithCollapsedSpace
|| (m_textBox == firstTextBox && textBoxStart == runStart && runStart > 0);
if (needSpace && !isCollapsibleWhitespace(m_lastCharacter) && m_lastCharacter) {
@@ -365,7 +469,7 @@ void TextIterator::handleTextBox()
int runEnd = min(textBoxEnd, end);
// Determine what the next text box will be, but don't advance yet
- InlineTextBox *nextTextBox = 0;
+ InlineTextBox* nextTextBox = 0;
if (renderer->containsReversedText()) {
if (m_sortedTextBoxesPosition + 1 < m_sortedTextBoxes.size())
nextTextBox = m_sortedTextBoxes[m_sortedTextBoxesPosition + 1];
@@ -411,6 +515,9 @@ void TextIterator::handleTextBox()
bool TextIterator::handleReplacedElement()
{
+ if (m_fullyClippedStack.top())
+ return false;
+
RenderObject* renderer = m_node->renderer();
if (renderer->style()->visibility() != VISIBLE)
return false;
@@ -421,10 +528,12 @@ bool TextIterator::handleReplacedElement()
}
if (m_enterTextControls && renderer->isTextControl()) {
- m_node = toRenderTextControl(renderer)->innerTextElement();
- m_offset = 0;
- m_inShadowContent = true;
- return false;
+ if (HTMLElement* innerTextElement = toRenderTextControl(renderer)->innerTextElement()) {
+ m_node = innerTextElement->shadowTreeRootNode();
+ pushFullyClippedState(m_fullyClippedStack, m_node);
+ m_offset = 0;
+ return false;
+ }
}
m_haveEmitted = true;
@@ -698,7 +807,7 @@ void TextIterator::exitNode()
emitCharacter(' ', baseNode->parentNode(), baseNode, 1, 1);
}
-void TextIterator::emitCharacter(UChar c, Node *textNode, Node *offsetBaseNode, int textStartOffset, int textEndOffset)
+void TextIterator::emitCharacter(UChar c, Node* textNode, Node* offsetBaseNode, int textStartOffset, int textEndOffset)
{
m_haveEmitted = true;
@@ -778,7 +887,7 @@ SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator() : m_positionN
{
}
-SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const Range *r)
+SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const Range* r)
{
m_positionNode = 0;
@@ -806,6 +915,7 @@ SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const Range *r)
}
m_node = endNode;
+ setUpFullyClippedStack(m_fullyClippedStack, m_node);
m_offset = endOffset;
m_handledNode = false;
m_handledChildren = endOffset == 0;
@@ -845,7 +955,7 @@ void SimplifiedBackwardsTextIterator::advance()
while (m_node && m_node != m_pastStartNode) {
// Don't handle node if we start iterating at [node, 0].
if (!m_handledNode && !(m_node == m_endNode && m_endOffset == 0)) {
- RenderObject *renderer = m_node->renderer();
+ RenderObject* renderer = m_node->renderer();
if (renderer && renderer->isText() && m_node->nodeType() == Node::TEXT_NODE) {
// FIXME: What about CDATA_SECTION_NODE?
if (renderer->style()->visibility() == VISIBLE && m_offset > 0)
@@ -877,9 +987,11 @@ void SimplifiedBackwardsTextIterator::advance()
// Exit all other containers.
next = m_node->previousSibling();
while (!next) {
- if (!m_node->parentNode())
+ Node* parentNode = parentOrShadowParent(m_node);
+ if (!parentNode)
break;
- m_node = m_node->parentNode();
+ m_node = parentNode;
+ m_fullyClippedStack.pop();
exitNode();
if (m_positionNode) {
m_handledNode = true;
@@ -888,9 +1000,12 @@ void SimplifiedBackwardsTextIterator::advance()
}
next = m_node->previousSibling();
}
+ m_fullyClippedStack.pop();
}
m_node = next;
+ if (m_node)
+ pushFullyClippedState(m_fullyClippedStack, m_node);
m_offset = m_node ? caretMaxOffset(m_node) : 0;
m_handledNode = false;
m_handledChildren = false;
@@ -904,7 +1019,7 @@ bool SimplifiedBackwardsTextIterator::handleTextNode()
{
m_lastTextNode = m_node;
- RenderText *renderer = toRenderText(m_node->renderer());
+ RenderText* renderer = toRenderText(m_node->renderer());
String str = renderer->text();
if (!renderer->firstTextBox() && str.length() > 0)
@@ -960,7 +1075,7 @@ void SimplifiedBackwardsTextIterator::exitNode()
emitCharacter('\n', m_node, 0, 0);
}
-void SimplifiedBackwardsTextIterator::emitCharacter(UChar c, Node *node, int startOffset, int endOffset)
+void SimplifiedBackwardsTextIterator::emitCharacter(UChar c, Node* node, int startOffset, int endOffset)
{
m_singleCharacterBuffer = c;
m_positionNode = node;
@@ -988,7 +1103,7 @@ CharacterIterator::CharacterIterator()
{
}
-CharacterIterator::CharacterIterator(const Range *r, bool emitCharactersBetweenAllVisiblePositions, bool enterTextControls)
+CharacterIterator::CharacterIterator(const Range* r, bool emitCharactersBetweenAllVisiblePositions, bool enterTextControls)
: m_offset(0)
, m_runOffset(0)
, m_atBreak(true)
@@ -1167,15 +1282,17 @@ void BackwardsCharacterIterator::advance(int count)
// --------
WordAwareIterator::WordAwareIterator()
-: m_previousText(0), m_didLookAhead(false)
+ : m_previousText(0)
+ , m_didLookAhead(false)
{
}
-WordAwareIterator::WordAwareIterator(const Range *r)
-: m_previousText(0), m_didLookAhead(false), m_textIterator(r)
+WordAwareIterator::WordAwareIterator(const Range* r)
+ : m_previousText(0)
+ , m_didLookAhead(true) // so we consider the first chunk from the text iterator
+ , m_textIterator(r)
{
- m_didLookAhead = true; // so we consider the first chunk from the text iterator
- advance(); // get in position over the first chunk of text
+ advance(); // get in position over the first chunk of text
}
// We're always in one of these modes:
@@ -1185,7 +1302,7 @@ WordAwareIterator::WordAwareIterator(const Range *r)
// (we looked ahead to the next chunk and found a word boundary)
// - We built up our own chunk of text from many chunks from the text iterator
-// FIXME: Perf could be bad for huge spans next to each other that don't fall on word boundaries
+// FIXME: Performance could be bad for huge spans next to each other that don't fall on word boundaries.
void WordAwareIterator::advance()
{
@@ -1507,7 +1624,7 @@ size_t SearchBuffer::length() const
// --------
-int TextIterator::rangeLength(const Range *r, bool forSelectionPreservation)
+int TextIterator::rangeLength(const Range* r, bool forSelectionPreservation)
{
int length = 0;
for (TextIterator it(r, forSelectionPreservation); !it.atEnd(); it.advance())
@@ -1522,7 +1639,7 @@ PassRefPtr<Range> TextIterator::subrange(Range* entireRange, int characterOffset
return characterSubrange(entireRangeIterator, characterOffset, characterCount);
}
-PassRefPtr<Range> TextIterator::rangeFromLocationAndLength(Element *scope, int rangeLocation, int rangeLength, bool forSelectionPreservation)
+PassRefPtr<Range> TextIterator::rangeFromLocationAndLength(Element* scope, int rangeLocation, int rangeLength, bool forSelectionPreservation)
{
RefPtr<Range> resultRange = scope->document()->createRange();