WebCore/rendering/InlineIterator.h
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebCore/rendering/InlineIterator.h	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010 Apple Inc. All right reserved.
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef InlineIterator_h
+#define InlineIterator_h
+
+#include "BidiRun.h"
+#include "RenderBlock.h"
+#include "RenderText.h"
+#include <wtf/AlwaysInline.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WebCore {
+
+class InlineIterator {
+public:
+    InlineIterator()
+        : block(0)
+        , obj(0)
+        , pos(0)
+        , nextBreakablePosition(-1)
+    {
+    }
+
+    InlineIterator(RenderBlock* b, RenderObject* o, unsigned p)
+        : block(b)
+        , obj(o)
+        , pos(p)
+        , nextBreakablePosition(-1)
+    {
+    }
+
+    void increment(InlineBidiResolver* resolver = 0);
+    bool atEnd() const;
+
+    UChar current() const;
+    WTF::Unicode::Direction direction() const;
+
+    RenderBlock* block;
+    RenderObject* obj;
+    unsigned pos;
+    int nextBreakablePosition;
+};
+
+inline bool operator==(const InlineIterator& it1, const InlineIterator& it2)
+{
+    return it1.pos == it2.pos && it1.obj == it2.obj;
+}
+
+inline bool operator!=(const InlineIterator& it1, const InlineIterator& it2)
+{
+    return it1.pos != it2.pos || it1.obj != it2.obj;
+}
+
+static inline RenderObject* bidiNext(RenderBlock* block, RenderObject* current, InlineBidiResolver* resolver = 0, bool skipInlines = true, bool* endOfInlinePtr = 0)
+{
+    RenderObject* next = 0;
+    bool oldEndOfInline = endOfInlinePtr ? *endOfInlinePtr : false;
+    bool endOfInline = false;
+
+    while (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);
+                }
+            }
+        }
+
+        if (!next) {
+            if (!skipInlines && !oldEndOfInline && current->isRenderInline()) {
+                next = current;
+                endOfInline = true;
+                break;
+            }
+
+            while (current && current != block) {
+                if (resolver && current->isRenderInline() && current->style()->unicodeBidi() != UBNormal)
+                    resolver->embed(WTF::Unicode::PopDirectionalFormat);
+
+                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);
+                        }
+                    }
+                    break;
+                }
+                
+                current = current->parent();
+                if (!skipInlines && current && current != block && current->isRenderInline()) {
+                    next = current;
+                    endOfInline = true;
+                    break;
+                }
+            }
+        }
+
+        if (!next)
+            break;
+
+        if (next->isText() || next->isFloating() || next->isReplaced() || next->isPositioned()
+            || ((!skipInlines || !next->firstChild()) // Always return EMPTY inlines.
+                && next->isRenderInline()))
+            break;
+        current = next;
+    }
+
+    if (endOfInlinePtr)
+        *endOfInlinePtr = endOfInline;
+
+    return next;
+}
+
+static inline RenderObject* bidiFirst(RenderBlock* block, InlineBidiResolver* resolver, bool skipInlines = true)
+{
+    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);
+            }
+        }
+        if (skipInlines && o->firstChild())
+            o = bidiNext(block, o, resolver, skipInlines);
+        else {
+            // Never skip empty inlines.
+            if (resolver)
+                resolver->commitExplicitEmbedding();
+            return o; 
+        }
+    }
+
+    if (o && !o->isText() && !o->isReplaced() && !o->isFloating() && !o->isPositioned())
+        o = bidiNext(block, o, resolver, skipInlines);
+
+    if (resolver)
+        resolver->commitExplicitEmbedding();
+    return o;
+}
+
+inline void InlineIterator::increment(InlineBidiResolver* resolver)
+{
+    if (!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;
+    }
+}
+
+inline bool InlineIterator::atEnd() const
+{
+    return !obj;
+}
+
+inline UChar InlineIterator::current() const
+{
+    if (!obj || !obj->isText())
+        return 0;
+
+    RenderText* text = toRenderText(obj);
+    if (pos >= text->textLength())
+        return 0;
+
+    return text->characters()[pos];
+}
+
+ALWAYS_INLINE WTF::Unicode::Direction InlineIterator::direction() const
+{
+    if (UChar c = current())
+        return WTF::Unicode::direction(c);
+
+    if (obj && obj->isListMarker())
+        return obj->style()->direction() == LTR ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;
+
+    return WTF::Unicode::OtherNeutral;
+}
+
+template<>
+inline void InlineBidiResolver::increment()
+{
+    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) {
+            RenderBlock::appendRunsForObject(start, obj->length(), obj, *this);        
+            start = 0;
+            obj = bidiNext(sor.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;
+            }
+            // 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;
+            RenderBlock::appendRunsForObject(start, end, obj, *this);
+        }
+        
+        eor.increment();
+        sor = eor;
+    }
+
+    m_direction = WTF::Unicode::OtherNeutral;
+    m_status.eor = WTF::Unicode::OtherNeutral;
+}
+
+}
+
+#endif // InlineIterator_h