Coverage Report

Created: 2018-09-25 14:53

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