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