Bug 1229437 part 3 - Support iterating frames of RubyColumn. r=dholbert
authorXidorn Quan <quanxunzhen@gmail.com>
Wed, 27 Jan 2016 16:58:53 +1100
changeset 281785 daa693feccc504cc84960971678b84f221681c8c
parent 281784 d26720c9d6a07ba9ca1a8d3b5d1d3aa6c9073220
child 281786 96478aae9d0ea1495806dc49683e356aec73e8e5
push id70926
push userxquan@mozilla.com
push dateWed, 27 Jan 2016 05:59:21 +0000
treeherdermozilla-inbound@f9c8ee9d178d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1229437
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1229437 part 3 - Support iterating frames of RubyColumn. r=dholbert
layout/generic/RubyUtils.cpp
layout/generic/RubyUtils.h
--- a/layout/generic/RubyUtils.cpp
+++ b/layout/generic/RubyUtils.cpp
@@ -52,16 +52,45 @@ AutoRubyTextContainerArray::AutoRubyText
 {
   for (nsIFrame* frame = aBaseContainer->GetNextSibling();
        frame && frame->GetType() == nsGkAtoms::rubyTextContainerFrame;
        frame = frame->GetNextSibling()) {
     AppendElement(static_cast<nsRubyTextContainerFrame*>(frame));
   }
 }
 
+nsIFrame*
+RubyColumn::Iterator::operator*() const
+{
+  nsIFrame* frame;
+  if (mIndex == -1) {
+    frame = mColumn.mBaseFrame;
+  } else {
+    frame = mColumn.mTextFrames[mIndex];
+  }
+  MOZ_ASSERT(frame, "Frame here cannot be null");
+  return frame;
+}
+
+void
+RubyColumn::Iterator::SkipUntilExistingFrame()
+{
+  if (mIndex == -1) {
+    if (!mColumn.mBaseFrame) {
+      ++mIndex;
+    }
+  }
+  auto numTextFrames = mColumn.mTextFrames.Length();
+  for (; mIndex < numTextFrames; ++mIndex) {
+    if (mColumn.mTextFrames[mIndex]) {
+      break;
+    }
+  }
+}
+
 RubySegmentEnumerator::RubySegmentEnumerator(nsRubyFrame* aRubyFrame)
 {
   nsIFrame* frame = aRubyFrame->GetFirstPrincipalChild();
   MOZ_ASSERT(!frame ||
              frame->GetType() == nsGkAtoms::rubyBaseContainerFrame);
   mBaseContainer = static_cast<nsRubyBaseContainerFrame*>(frame);
 }
 
--- a/layout/generic/RubyUtils.h
+++ b/layout/generic/RubyUtils.h
@@ -128,17 +128,64 @@ private:
  * annotations paired with it.
  * See http://dev.w3.org/csswg/css-ruby/#ruby-pairing
  */
 struct MOZ_STACK_CLASS RubyColumn
 {
   nsRubyBaseFrame* mBaseFrame;
   nsAutoTArray<nsRubyTextFrame*, RTC_ARRAY_SIZE> mTextFrames;
   bool mIsIntraLevelWhitespace;
+
   RubyColumn() : mBaseFrame(nullptr), mIsIntraLevelWhitespace(false) { }
+
+  // Helper class to support iteration across the frames within a single
+  // RubyColumn (the column's ruby base and its annotations).
+  class MOZ_STACK_CLASS Iterator
+  {
+  public:
+    nsIFrame* operator*() const;
+
+    Iterator& operator++() { ++mIndex; SkipUntilExistingFrame(); return *this; }
+    Iterator operator++(int) { auto ret = *this; ++*this; return ret; }
+
+    friend bool operator==(const Iterator& aIter1, const Iterator& aIter2)
+    {
+      MOZ_ASSERT(&aIter1.mColumn == &aIter2.mColumn,
+                 "Should only compare iterators of the same ruby column");
+      return aIter1.mIndex == aIter2.mIndex;
+    }
+    friend bool operator!=(const Iterator& aIter1, const Iterator& aIter2)
+    {
+      return !(aIter1 == aIter2);
+    }
+
+  private:
+    Iterator(const RubyColumn& aColumn, int32_t aIndex)
+      : mColumn(aColumn)
+      , mIndex(aIndex)
+    {
+      MOZ_ASSERT(aIndex == -1 ||
+                 (aIndex >= 0 && aIndex <= aColumn.mTextFrames.Length()));
+      SkipUntilExistingFrame();
+    }
+    friend struct RubyColumn; // for the constructor
+
+    void SkipUntilExistingFrame();
+
+    const RubyColumn& mColumn;
+    // -1 means the ruby base frame,
+    // non-negative means the index of ruby text frame
+    // a value of mTextFrames.Length() means we're done iterating
+    int32_t mIndex = -1;
+  };
+
+  Iterator begin() const { return Iterator(*this, -1); }
+  Iterator end() const { return Iterator(*this, mTextFrames.Length()); }
+  Iterator cbegin() const { return begin(); }
+  Iterator cend() const { return end(); }
 };
 
 /**
  * This enumerator enumerates ruby columns in a segment.
  */
 class MOZ_STACK_CLASS RubyColumnEnumerator
 {
 public: