tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RubyUtils.cpp (7023B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "RubyUtils.h"
      8 
      9 #include "nsRubyBaseContainerFrame.h"
     10 #include "nsRubyBaseFrame.h"
     11 #include "nsRubyFrame.h"
     12 #include "nsRubyTextContainerFrame.h"
     13 #include "nsRubyTextFrame.h"
     14 
     15 using namespace mozilla;
     16 
     17 NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(ReservedISize, nscoord)
     18 
     19 /* static */
     20 void RubyUtils::SetReservedISize(nsIFrame* aFrame, nscoord aISize) {
     21  MOZ_ASSERT(IsExpandableRubyBox(aFrame));
     22  aFrame->SetProperty(ReservedISize(), aISize);
     23 }
     24 
     25 /* static */
     26 void RubyUtils::ClearReservedISize(nsIFrame* aFrame) {
     27  MOZ_ASSERT(IsExpandableRubyBox(aFrame));
     28  aFrame->RemoveProperty(ReservedISize());
     29 }
     30 
     31 /* static */
     32 nscoord RubyUtils::GetReservedISize(nsIFrame* aFrame) {
     33  MOZ_ASSERT(IsExpandableRubyBox(aFrame));
     34  return aFrame->GetProperty(ReservedISize());
     35 }
     36 
     37 AutoRubyTextContainerArray::AutoRubyTextContainerArray(
     38    nsRubyBaseContainerFrame* aBaseContainer) {
     39  for (nsIFrame* frame = aBaseContainer->GetNextSibling();
     40       frame && frame->IsRubyTextContainerFrame();
     41       frame = frame->GetNextSibling()) {
     42    AppendElement(static_cast<nsRubyTextContainerFrame*>(frame));
     43  }
     44 }
     45 
     46 nsIFrame* RubyColumn::Iterator::operator*() const {
     47  nsIFrame* frame;
     48  if (mIndex == -1) {
     49    frame = mColumn.mBaseFrame;
     50  } else {
     51    frame = mColumn.mTextFrames[mIndex];
     52  }
     53  MOZ_ASSERT(frame, "Frame here cannot be null");
     54  return frame;
     55 }
     56 
     57 void RubyColumn::Iterator::SkipUntilExistingFrame() {
     58  if (mIndex == -1) {
     59    if (mColumn.mBaseFrame) {
     60      return;
     61    }
     62    ++mIndex;
     63  }
     64  int32_t numTextFrames = mColumn.mTextFrames.Length();
     65  for (; mIndex < numTextFrames; ++mIndex) {
     66    if (mColumn.mTextFrames[mIndex]) {
     67      break;
     68    }
     69  }
     70 }
     71 
     72 RubySegmentEnumerator::RubySegmentEnumerator(nsRubyFrame* aRubyFrame) {
     73  nsIFrame* frame = aRubyFrame->PrincipalChildList().FirstChild();
     74  MOZ_ASSERT(!frame || frame->IsRubyBaseContainerFrame());
     75  mBaseContainer = static_cast<nsRubyBaseContainerFrame*>(frame);
     76 }
     77 
     78 void RubySegmentEnumerator::Next() {
     79  MOZ_ASSERT(mBaseContainer);
     80  nsIFrame* frame = mBaseContainer->GetNextSibling();
     81  while (frame && !frame->IsRubyBaseContainerFrame()) {
     82    frame = frame->GetNextSibling();
     83  }
     84  mBaseContainer = static_cast<nsRubyBaseContainerFrame*>(frame);
     85 }
     86 
     87 RubyColumnEnumerator::RubyColumnEnumerator(
     88    nsRubyBaseContainerFrame* aBaseContainer,
     89    const AutoRubyTextContainerArray& aTextContainers)
     90    : mAtIntraLevelWhitespace(false) {
     91  const uint32_t rtcCount = aTextContainers.Length();
     92  mFrames.SetCapacity(rtcCount + 1);
     93 
     94  nsIFrame* rbFrame = aBaseContainer->PrincipalChildList().FirstChild();
     95  MOZ_ASSERT(!rbFrame || rbFrame->IsRubyBaseFrame());
     96  mFrames.AppendElement(static_cast<nsRubyContentFrame*>(rbFrame));
     97  for (uint32_t i = 0; i < rtcCount; i++) {
     98    nsRubyTextContainerFrame* container = aTextContainers[i];
     99    // If the container is for span, leave a nullptr here.
    100    // Spans do not take part in pairing.
    101    nsIFrame* rtFrame = !container->IsSpanContainer()
    102                            ? container->PrincipalChildList().FirstChild()
    103                            : nullptr;
    104    MOZ_ASSERT(!rtFrame || rtFrame->IsRubyTextFrame());
    105    mFrames.AppendElement(static_cast<nsRubyContentFrame*>(rtFrame));
    106  }
    107 
    108  // We have to init mAtIntraLevelWhitespace to be correct for the
    109  // first column. There are two ways we could end up with intra-level
    110  // whitespace in our first colum:
    111  // 1. The current segment itself is an inter-segment whitespace;
    112  // 2. If our ruby segment is split across multiple lines, and some
    113  //    intra-level whitespace happens to fall right after a line-break.
    114  //    Each line will get its own nsRubyBaseContainerFrame, and the
    115  //    container right after the line-break will end up with its first
    116  //    column containing that intra-level whitespace.
    117  for (uint32_t i = 0, iend = mFrames.Length(); i < iend; i++) {
    118    nsRubyContentFrame* frame = mFrames[i];
    119    if (frame && frame->IsIntraLevelWhitespace()) {
    120      mAtIntraLevelWhitespace = true;
    121      break;
    122    }
    123  }
    124 }
    125 
    126 void RubyColumnEnumerator::Next() {
    127  bool advancingToIntraLevelWhitespace = false;
    128  for (uint32_t i = 0, iend = mFrames.Length(); i < iend; i++) {
    129    nsRubyContentFrame* frame = mFrames[i];
    130    // If we've got intra-level whitespace frames at some levels in the
    131    // current ruby column, we "faked" an anonymous box for all other
    132    // levels for this column. So when we advance off this column, we
    133    // don't advance any of the frames in those levels, because we're
    134    // just advancing across the "fake" frames.
    135    if (frame &&
    136        (!mAtIntraLevelWhitespace || frame->IsIntraLevelWhitespace())) {
    137      nsIFrame* nextSibling = frame->GetNextSibling();
    138      MOZ_ASSERT(!nextSibling || nextSibling->Type() == frame->Type(),
    139                 "Frame type should be identical among a level");
    140      mFrames[i] = frame = static_cast<nsRubyContentFrame*>(nextSibling);
    141      if (!advancingToIntraLevelWhitespace && frame &&
    142          frame->IsIntraLevelWhitespace()) {
    143        advancingToIntraLevelWhitespace = true;
    144      }
    145    }
    146  }
    147  MOZ_ASSERT(!advancingToIntraLevelWhitespace || !mAtIntraLevelWhitespace,
    148             "Should never have adjacent intra-level whitespace columns");
    149  mAtIntraLevelWhitespace = advancingToIntraLevelWhitespace;
    150 }
    151 
    152 bool RubyColumnEnumerator::AtEnd() const {
    153  for (uint32_t i = 0, iend = mFrames.Length(); i < iend; i++) {
    154    if (mFrames[i]) {
    155      return false;
    156    }
    157  }
    158  return true;
    159 }
    160 
    161 nsRubyContentFrame* RubyColumnEnumerator::GetFrameAtLevel(
    162    uint32_t aIndex) const {
    163  // If the current ruby column is for intra-level whitespaces, we
    164  // return nullptr for any levels that do not have an actual intra-
    165  // level whitespace frame in this column.  This nullptr represents
    166  // an anonymous empty intra-level whitespace box.  (In this case,
    167  // it's important that we NOT return mFrames[aIndex], because it's
    168  // really part of the next column, not the current one.)
    169  nsRubyContentFrame* frame = mFrames[aIndex];
    170  return !mAtIntraLevelWhitespace || (frame && frame->IsIntraLevelWhitespace())
    171             ? frame
    172             : nullptr;
    173 }
    174 
    175 void RubyColumnEnumerator::GetColumn(RubyColumn& aColumn) const {
    176  nsRubyContentFrame* rbFrame = GetFrameAtLevel(0);
    177  MOZ_ASSERT(!rbFrame || rbFrame->IsRubyBaseFrame());
    178  aColumn.mBaseFrame = static_cast<nsRubyBaseFrame*>(rbFrame);
    179  aColumn.mTextFrames.ClearAndRetainStorage();
    180  for (uint32_t i = 1, iend = mFrames.Length(); i < iend; i++) {
    181    nsRubyContentFrame* rtFrame = GetFrameAtLevel(i);
    182    MOZ_ASSERT(!rtFrame || rtFrame->IsRubyTextFrame());
    183    aColumn.mTextFrames.AppendElement(static_cast<nsRubyTextFrame*>(rtFrame));
    184  }
    185  aColumn.mIsIntraLevelWhitespace = mAtIntraLevelWhitespace;
    186 }