Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/generic/BRFrame.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
/* rendering object for HTML <br> elements */
8
9
#include "gfxContext.h"
10
#include "nsCOMPtr.h"
11
#include "nsContainerFrame.h"
12
#include "nsFontMetrics.h"
13
#include "nsFrame.h"
14
#include "nsPresContext.h"
15
#include "nsLineLayout.h"
16
#include "nsStyleConsts.h"
17
#include "nsGkAtoms.h"
18
#include "nsLayoutUtils.h"
19
20
//FOR SELECTION
21
#include "nsIContent.h"
22
//END INCLUDES FOR SELECTION
23
24
using namespace mozilla;
25
26
namespace mozilla {
27
28
class BRFrame final : public nsFrame
29
{
30
public:
31
  NS_DECL_FRAMEARENA_HELPERS(BRFrame)
32
33
  friend nsIFrame* ::NS_NewBRFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
34
35
  ContentOffsets CalcContentOffsetsFromFramePoint(const nsPoint& aPoint) override;
36
37
  virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) override;
38
  virtual FrameSearchResult
39
  PeekOffsetCharacter(bool aForward, int32_t* aOffset,
40
                      PeekOffsetCharacterOptions aOptions =
41
                        PeekOffsetCharacterOptions()) override;
42
  virtual FrameSearchResult PeekOffsetWord(bool aForward, bool aWordSelectEatSpace,
43
                              bool aIsKeyboardSelect, int32_t* aOffset,
44
                              PeekWordState* aState) override;
45
46
  virtual void Reflow(nsPresContext* aPresContext,
47
                          ReflowOutput& aDesiredSize,
48
                          const ReflowInput& aReflowInput,
49
                          nsReflowStatus& aStatus) override;
50
  virtual void AddInlineMinISize(gfxContext *aRenderingContext,
51
                                 InlineMinISizeData *aData) override;
52
  virtual void AddInlinePrefISize(gfxContext *aRenderingContext,
53
                                  InlinePrefISizeData *aData) override;
54
  virtual nscoord GetMinISize(gfxContext *aRenderingContext) override;
55
  virtual nscoord GetPrefISize(gfxContext *aRenderingContext) override;
56
  virtual nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const override;
57
58
  virtual bool IsFrameOfType(uint32_t aFlags) const override
59
0
  {
60
0
    return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced |
61
0
                                             nsIFrame::eLineParticipant));
62
0
  }
63
64
#ifdef ACCESSIBILITY
65
  virtual mozilla::a11y::AccType AccessibleType() override;
66
#endif
67
68
protected:
69
  explicit BRFrame(ComputedStyle* aStyle)
70
    : nsFrame(aStyle, kClassID)
71
    , mAscent(NS_INTRINSIC_WIDTH_UNKNOWN)
72
0
  {}
73
74
  virtual ~BRFrame();
75
76
  nscoord mAscent;
77
};
78
79
} // namespace mozilla
80
81
nsIFrame*
82
NS_NewBRFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
83
0
{
84
0
  return new (aPresShell) BRFrame(aStyle);
85
0
}
86
87
NS_IMPL_FRAMEARENA_HELPERS(BRFrame)
88
89
BRFrame::~BRFrame()
90
0
{
91
0
}
92
93
void
94
BRFrame::Reflow(nsPresContext* aPresContext,
95
                ReflowOutput& aMetrics,
96
                const ReflowInput& aReflowInput,
97
                nsReflowStatus& aStatus)
98
0
{
99
0
  MarkInReflow();
100
0
  DO_GLOBAL_REFLOW_COUNT("BRFrame");
101
0
  DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
102
0
  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
103
0
104
0
  WritingMode wm = aReflowInput.GetWritingMode();
105
0
  LogicalSize finalSize(wm);
106
0
  finalSize.BSize(wm) = 0; // BR frames with block size 0 are ignored in quirks
107
0
                           // mode by nsLineLayout::VerticalAlignFrames .
108
0
                           // However, it's not always 0.  See below.
109
0
  finalSize.ISize(wm) = 0;
110
0
  aMetrics.SetBlockStartAscent(0);
111
0
112
0
  // Only when the BR is operating in a line-layout situation will it
113
0
  // behave like a BR. Additionally, we suppress breaks from BR inside
114
0
  // of ruby frames. To determine if we're inside ruby, we have to rely
115
0
  // on the *parent's* ShouldSuppressLineBreak() method, instead of our
116
0
  // own, because we may have custom "display" value that makes our
117
0
  // ShouldSuppressLineBreak() return false.
118
0
  nsLineLayout* ll = aReflowInput.mLineLayout;
119
0
  if (ll && !GetParent()->Style()->ShouldSuppressLineBreak()) {
120
0
    // Note that the compatibility mode check excludes AlmostStandards
121
0
    // mode, since this is the inline box model.  See bug 161691.
122
0
    if ( ll->LineIsEmpty() ||
123
0
         aPresContext->CompatibilityMode() == eCompatibility_FullStandards ) {
124
0
      // The line is logically empty; any whitespace is trimmed away.
125
0
      //
126
0
      // If this frame is going to terminate the line we know
127
0
      // that nothing else will go on the line. Therefore, in this
128
0
      // case, we provide some height for the BR frame so that it
129
0
      // creates some vertical whitespace.  It's necessary to use the
130
0
      // line-height rather than the font size because the
131
0
      // quirks-mode fix that doesn't apply the block's min
132
0
      // line-height makes this necessary to make BR cause a line
133
0
      // of the full line-height
134
0
135
0
      // We also do this in strict mode because BR should act like a
136
0
      // normal inline frame.  That line-height is used is important
137
0
      // here for cases where the line-height is less than 1.
138
0
      RefPtr<nsFontMetrics> fm =
139
0
        nsLayoutUtils::GetInflatedFontMetricsForFrame(this);
140
0
      if (fm) {
141
0
        nscoord logicalHeight = aReflowInput.CalcLineHeight();
142
0
        finalSize.BSize(wm) = logicalHeight;
143
0
        aMetrics.SetBlockStartAscent(nsLayoutUtils::GetCenteredFontBaseline(
144
0
                                       fm, logicalHeight, wm.IsLineInverted()));
145
0
      }
146
0
      else {
147
0
        aMetrics.SetBlockStartAscent(aMetrics.BSize(wm) = 0);
148
0
      }
149
0
150
0
      // XXX temporary until I figure out a better solution; see the
151
0
      // code in nsLineLayout::VerticalAlignFrames that zaps minY/maxY
152
0
      // if the width is zero.
153
0
      // XXX This also fixes bug 10036!
154
0
      // Warning: nsTextControlFrame::CalculateSizeStandard depends on
155
0
      // the following line, see bug 228752.
156
0
      // The code below in AddInlinePrefISize also adds 1 appunit to width
157
0
      finalSize.ISize(wm) = 1;
158
0
    }
159
0
160
0
    // Return our reflow status
161
0
    StyleClear breakType = aReflowInput.mStyleDisplay->mBreakType;
162
0
    if (StyleClear::None == breakType) {
163
0
      breakType = StyleClear::Line;
164
0
    }
165
0
166
0
    aStatus.SetInlineLineBreakAfter(breakType);
167
0
    ll->SetLineEndsInBR(true);
168
0
  }
169
0
170
0
  aMetrics.SetSize(wm, finalSize);
171
0
  aMetrics.SetOverflowAreasToDesiredBounds();
172
0
173
0
  mAscent = aMetrics.BlockStartAscent();
174
0
175
0
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics);
176
0
}
177
178
/* virtual */ void
179
BRFrame::AddInlineMinISize(gfxContext *aRenderingContext,
180
                           nsIFrame::InlineMinISizeData *aData)
181
0
{
182
0
  if (!GetParent()->Style()->ShouldSuppressLineBreak()) {
183
0
    aData->ForceBreak();
184
0
  }
185
0
}
186
187
/* virtual */ void
188
BRFrame::AddInlinePrefISize(gfxContext *aRenderingContext,
189
                            nsIFrame::InlinePrefISizeData *aData)
190
0
{
191
0
  if (!GetParent()->Style()->ShouldSuppressLineBreak()) {
192
0
    // Match the 1 appunit width assigned in the Reflow method above
193
0
    aData->mCurrentLine += 1;
194
0
    aData->ForceBreak();
195
0
  }
196
0
}
197
198
/* virtual */ nscoord
199
BRFrame::GetMinISize(gfxContext *aRenderingContext)
200
0
{
201
0
  nscoord result = 0;
202
0
  DISPLAY_MIN_INLINE_SIZE(this, result);
203
0
  return result;
204
0
}
205
206
/* virtual */ nscoord
207
BRFrame::GetPrefISize(gfxContext *aRenderingContext)
208
0
{
209
0
  nscoord result = 0;
210
0
  DISPLAY_PREF_INLINE_SIZE(this, result);
211
0
  return result;
212
0
}
213
214
nscoord
215
BRFrame::GetLogicalBaseline(mozilla::WritingMode aWritingMode) const
216
0
{
217
0
  return mAscent;
218
0
}
219
220
nsIFrame::ContentOffsets BRFrame::CalcContentOffsetsFromFramePoint(const nsPoint& aPoint)
221
0
{
222
0
  ContentOffsets offsets;
223
0
  offsets.content = mContent->GetParent();
224
0
  if (offsets.content) {
225
0
    offsets.offset = offsets.content->ComputeIndexOf(mContent);
226
0
    offsets.secondaryOffset = offsets.offset;
227
0
    offsets.associate = CARET_ASSOCIATE_AFTER;
228
0
  }
229
0
  return offsets;
230
0
}
231
232
nsIFrame::FrameSearchResult
233
BRFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset)
234
0
{
235
0
  NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
236
0
  int32_t startOffset = *aOffset;
237
0
  // If we hit the end of a BR going backwards, go to its beginning and stay there.
238
0
  if (!aForward && startOffset != 0) {
239
0
    *aOffset = 0;
240
0
    return FOUND;
241
0
  }
242
0
  // Otherwise, stop if we hit the beginning, continue (forward) if we hit the end.
243
0
  return (startOffset == 0) ? FOUND : CONTINUE;
244
0
}
245
246
nsIFrame::FrameSearchResult
247
BRFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
248
                             PeekOffsetCharacterOptions aOptions)
249
0
{
250
0
  NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
251
0
  // Keep going. The actual line jumping will stop us.
252
0
  return CONTINUE;
253
0
}
254
255
nsIFrame::FrameSearchResult
256
BRFrame::PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
257
                        int32_t* aOffset, PeekWordState* aState)
258
0
{
259
0
  NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
260
0
  // Keep going. The actual line jumping will stop us.
261
0
  return CONTINUE;
262
0
}
263
264
#ifdef ACCESSIBILITY
265
a11y::AccType
266
BRFrame::AccessibleType()
267
0
{
268
0
  nsIContent *parent = mContent->GetParent();
269
0
  if (parent && parent->IsRootOfNativeAnonymousSubtree() &&
270
0
      parent->GetChildCount() == 1) {
271
0
    // This <br> is the only node in a text control, therefore it is the hacky
272
0
    // "bogus node" used when there is no text in the control
273
0
    return a11y::eNoType;
274
0
  }
275
0
276
0
  // Trailing HTML br element don't play any difference. We don't need to expose
277
0
  // it to AT (see bug https://bugzilla.mozilla.org/show_bug.cgi?id=899433#c16
278
0
  // for details).
279
0
  if (!mContent->GetNextSibling() && !GetNextSibling()) {
280
0
    return a11y::eNoType;
281
0
  }
282
0
283
0
  return a11y::eHTMLBRType;
284
0
}
285
#endif
286