|
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 "nsCOMPtr.h" |
|
9 #include "nsFrame.h" |
|
10 #include "nsPresContext.h" |
|
11 #include "nsLineLayout.h" |
|
12 #include "nsStyleConsts.h" |
|
13 #include "nsGkAtoms.h" |
|
14 #include "nsRenderingContext.h" |
|
15 #include "nsLayoutUtils.h" |
|
16 |
|
17 //FOR SELECTION |
|
18 #include "nsIContent.h" |
|
19 //END INCLUDES FOR SELECTION |
|
20 |
|
21 using namespace mozilla; |
|
22 |
|
23 class BRFrame : public nsFrame { |
|
24 public: |
|
25 NS_DECL_FRAMEARENA_HELPERS |
|
26 |
|
27 friend nsIFrame* NS_NewBRFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); |
|
28 |
|
29 virtual ContentOffsets CalcContentOffsetsFromFramePoint(nsPoint aPoint) MOZ_OVERRIDE; |
|
30 |
|
31 virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) MOZ_OVERRIDE; |
|
32 virtual FrameSearchResult PeekOffsetCharacter(bool aForward, int32_t* aOffset, |
|
33 bool aRespectClusters = true) MOZ_OVERRIDE; |
|
34 virtual FrameSearchResult PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, |
|
35 bool aIsKeyboardSelect, int32_t* aOffset, |
|
36 PeekWordState* aState) MOZ_OVERRIDE; |
|
37 |
|
38 virtual nsresult Reflow(nsPresContext* aPresContext, |
|
39 nsHTMLReflowMetrics& aDesiredSize, |
|
40 const nsHTMLReflowState& aReflowState, |
|
41 nsReflowStatus& aStatus) MOZ_OVERRIDE; |
|
42 virtual void AddInlineMinWidth(nsRenderingContext *aRenderingContext, |
|
43 InlineMinWidthData *aData) MOZ_OVERRIDE; |
|
44 virtual void AddInlinePrefWidth(nsRenderingContext *aRenderingContext, |
|
45 InlinePrefWidthData *aData) MOZ_OVERRIDE; |
|
46 virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; |
|
47 virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; |
|
48 virtual nsIAtom* GetType() const MOZ_OVERRIDE; |
|
49 virtual nscoord GetBaseline() const MOZ_OVERRIDE; |
|
50 |
|
51 virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE |
|
52 { |
|
53 return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced | |
|
54 nsIFrame::eLineParticipant)); |
|
55 } |
|
56 |
|
57 #ifdef ACCESSIBILITY |
|
58 virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE; |
|
59 #endif |
|
60 |
|
61 protected: |
|
62 BRFrame(nsStyleContext* aContext) : nsFrame(aContext) {} |
|
63 virtual ~BRFrame(); |
|
64 |
|
65 nscoord mAscent; |
|
66 }; |
|
67 |
|
68 nsIFrame* |
|
69 NS_NewBRFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) |
|
70 { |
|
71 return new (aPresShell) BRFrame(aContext); |
|
72 } |
|
73 |
|
74 NS_IMPL_FRAMEARENA_HELPERS(BRFrame) |
|
75 |
|
76 BRFrame::~BRFrame() |
|
77 { |
|
78 } |
|
79 |
|
80 nsresult |
|
81 BRFrame::Reflow(nsPresContext* aPresContext, |
|
82 nsHTMLReflowMetrics& aMetrics, |
|
83 const nsHTMLReflowState& aReflowState, |
|
84 nsReflowStatus& aStatus) |
|
85 { |
|
86 DO_GLOBAL_REFLOW_COUNT("BRFrame"); |
|
87 DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); |
|
88 aMetrics.Height() = 0; // BR frames with height 0 are ignored in quirks |
|
89 // mode by nsLineLayout::VerticalAlignFrames . |
|
90 // However, it's not always 0. See below. |
|
91 aMetrics.Width() = 0; |
|
92 aMetrics.SetTopAscent(0); |
|
93 |
|
94 // Only when the BR is operating in a line-layout situation will it |
|
95 // behave like a BR. |
|
96 nsLineLayout* ll = aReflowState.mLineLayout; |
|
97 if (ll) { |
|
98 // Note that the compatibility mode check excludes AlmostStandards |
|
99 // mode, since this is the inline box model. See bug 161691. |
|
100 if ( ll->LineIsEmpty() || |
|
101 aPresContext->CompatibilityMode() == eCompatibility_FullStandards ) { |
|
102 // The line is logically empty; any whitespace is trimmed away. |
|
103 // |
|
104 // If this frame is going to terminate the line we know |
|
105 // that nothing else will go on the line. Therefore, in this |
|
106 // case, we provide some height for the BR frame so that it |
|
107 // creates some vertical whitespace. It's necessary to use the |
|
108 // line-height rather than the font size because the |
|
109 // quirks-mode fix that doesn't apply the block's min |
|
110 // line-height makes this necessary to make BR cause a line |
|
111 // of the full line-height |
|
112 |
|
113 // We also do this in strict mode because BR should act like a |
|
114 // normal inline frame. That line-height is used is important |
|
115 // here for cases where the line-height is less than 1. |
|
116 nsRefPtr<nsFontMetrics> fm; |
|
117 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), |
|
118 nsLayoutUtils::FontSizeInflationFor(this)); |
|
119 aReflowState.rendContext->SetFont(fm); // FIXME: maybe not needed? |
|
120 if (fm) { |
|
121 nscoord logicalHeight = aReflowState.CalcLineHeight(); |
|
122 aMetrics.Height() = logicalHeight; |
|
123 aMetrics.SetTopAscent(nsLayoutUtils::GetCenteredFontBaseline(fm, logicalHeight)); |
|
124 } |
|
125 else { |
|
126 aMetrics.SetTopAscent(aMetrics.Height() = 0); |
|
127 } |
|
128 |
|
129 // XXX temporary until I figure out a better solution; see the |
|
130 // code in nsLineLayout::VerticalAlignFrames that zaps minY/maxY |
|
131 // if the width is zero. |
|
132 // XXX This also fixes bug 10036! |
|
133 // Warning: nsTextControlFrame::CalculateSizeStandard depends on |
|
134 // the following line, see bug 228752. |
|
135 aMetrics.Width() = 1; |
|
136 } |
|
137 |
|
138 // Return our reflow status |
|
139 uint32_t breakType = aReflowState.mStyleDisplay->mBreakType; |
|
140 if (NS_STYLE_CLEAR_NONE == breakType) { |
|
141 breakType = NS_STYLE_CLEAR_LINE; |
|
142 } |
|
143 |
|
144 aStatus = NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER | |
|
145 NS_INLINE_MAKE_BREAK_TYPE(breakType); |
|
146 ll->SetLineEndsInBR(true); |
|
147 } |
|
148 else { |
|
149 aStatus = NS_FRAME_COMPLETE; |
|
150 } |
|
151 |
|
152 aMetrics.SetOverflowAreasToDesiredBounds(); |
|
153 |
|
154 mAscent = aMetrics.TopAscent(); |
|
155 |
|
156 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); |
|
157 return NS_OK; |
|
158 } |
|
159 |
|
160 /* virtual */ void |
|
161 BRFrame::AddInlineMinWidth(nsRenderingContext *aRenderingContext, |
|
162 nsIFrame::InlineMinWidthData *aData) |
|
163 { |
|
164 aData->ForceBreak(aRenderingContext); |
|
165 } |
|
166 |
|
167 /* virtual */ void |
|
168 BRFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext, |
|
169 nsIFrame::InlinePrefWidthData *aData) |
|
170 { |
|
171 aData->ForceBreak(aRenderingContext); |
|
172 } |
|
173 |
|
174 /* virtual */ nscoord |
|
175 BRFrame::GetMinWidth(nsRenderingContext *aRenderingContext) |
|
176 { |
|
177 nscoord result = 0; |
|
178 DISPLAY_MIN_WIDTH(this, result); |
|
179 return result; |
|
180 } |
|
181 |
|
182 /* virtual */ nscoord |
|
183 BRFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) |
|
184 { |
|
185 nscoord result = 0; |
|
186 DISPLAY_PREF_WIDTH(this, result); |
|
187 return result; |
|
188 } |
|
189 |
|
190 nsIAtom* |
|
191 BRFrame::GetType() const |
|
192 { |
|
193 return nsGkAtoms::brFrame; |
|
194 } |
|
195 |
|
196 nscoord |
|
197 BRFrame::GetBaseline() const |
|
198 { |
|
199 return mAscent; |
|
200 } |
|
201 |
|
202 nsIFrame::ContentOffsets BRFrame::CalcContentOffsetsFromFramePoint(nsPoint aPoint) |
|
203 { |
|
204 ContentOffsets offsets; |
|
205 offsets.content = mContent->GetParent(); |
|
206 if (offsets.content) { |
|
207 offsets.offset = offsets.content->IndexOf(mContent); |
|
208 offsets.secondaryOffset = offsets.offset; |
|
209 offsets.associateWithNext = true; |
|
210 } |
|
211 return offsets; |
|
212 } |
|
213 |
|
214 nsIFrame::FrameSearchResult |
|
215 BRFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset) |
|
216 { |
|
217 NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range"); |
|
218 int32_t startOffset = *aOffset; |
|
219 // If we hit the end of a BR going backwards, go to its beginning and stay there. |
|
220 if (!aForward && startOffset != 0) { |
|
221 *aOffset = 0; |
|
222 return FOUND; |
|
223 } |
|
224 // Otherwise, stop if we hit the beginning, continue (forward) if we hit the end. |
|
225 return (startOffset == 0) ? FOUND : CONTINUE; |
|
226 } |
|
227 |
|
228 nsIFrame::FrameSearchResult |
|
229 BRFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset, |
|
230 bool aRespectClusters) |
|
231 { |
|
232 NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range"); |
|
233 // Keep going. The actual line jumping will stop us. |
|
234 return CONTINUE; |
|
235 } |
|
236 |
|
237 nsIFrame::FrameSearchResult |
|
238 BRFrame::PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect, |
|
239 int32_t* aOffset, PeekWordState* aState) |
|
240 { |
|
241 NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range"); |
|
242 // Keep going. The actual line jumping will stop us. |
|
243 return CONTINUE; |
|
244 } |
|
245 |
|
246 #ifdef ACCESSIBILITY |
|
247 a11y::AccType |
|
248 BRFrame::AccessibleType() |
|
249 { |
|
250 nsIContent *parent = mContent->GetParent(); |
|
251 if (parent && parent->IsRootOfNativeAnonymousSubtree() && |
|
252 parent->GetChildCount() == 1) { |
|
253 // This <br> is the only node in a text control, therefore it is the hacky |
|
254 // "bogus node" used when there is no text in the control |
|
255 return a11y::eNoType; |
|
256 } |
|
257 |
|
258 return a11y::eHTMLBRType; |
|
259 } |
|
260 #endif |
|
261 |