/src/mozilla-central/layout/generic/nsLineLayout.h
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 | | /* state and methods used while laying out a single line of a block frame */ |
8 | | |
9 | | #ifndef nsLineLayout_h___ |
10 | | #define nsLineLayout_h___ |
11 | | |
12 | | #include "gfxTypes.h" |
13 | | #include "JustificationUtils.h" |
14 | | #include "mozilla/ArenaAllocator.h" |
15 | | #include "mozilla/WritingModes.h" |
16 | | #include "BlockReflowInput.h" |
17 | | #include "nsLineBox.h" |
18 | | |
19 | | class nsBulletFrame; |
20 | | class nsFloatManager; |
21 | | struct nsStyleText; |
22 | | |
23 | | class nsLineLayout { |
24 | | using BlockReflowInput = mozilla::BlockReflowInput; |
25 | | using ReflowInput = mozilla::ReflowInput; |
26 | | using ReflowOutput = mozilla::ReflowOutput; |
27 | | |
28 | | public: |
29 | | /** |
30 | | * @param aBaseLineLayout the nsLineLayout for ruby base, |
31 | | * nullptr if no separate base nsLineLayout is needed. |
32 | | */ |
33 | | nsLineLayout(nsPresContext* aPresContext, |
34 | | nsFloatManager* aFloatManager, |
35 | | const ReflowInput* aOuterReflowInput, |
36 | | const nsLineList::iterator* aLine, |
37 | | nsLineLayout* aBaseLineLayout); |
38 | | ~nsLineLayout(); |
39 | | |
40 | | void Init(BlockReflowInput* aState, nscoord aMinLineBSize, |
41 | 0 | int32_t aLineNumber) { |
42 | 0 | mBlockRI = aState; |
43 | 0 | mMinLineBSize = aMinLineBSize; |
44 | 0 | mLineNumber = aLineNumber; |
45 | 0 | } |
46 | | |
47 | 0 | int32_t GetLineNumber() const { |
48 | 0 | return mLineNumber; |
49 | 0 | } |
50 | | |
51 | | void BeginLineReflow(nscoord aICoord, nscoord aBCoord, |
52 | | nscoord aISize, nscoord aBSize, |
53 | | bool aImpactedByFloats, |
54 | | bool aIsTopOfPage, |
55 | | mozilla::WritingMode aWritingMode, |
56 | | const nsSize& aContainerSize); |
57 | | |
58 | | void EndLineReflow(); |
59 | | |
60 | | /** |
61 | | * Called when a float has been placed. This method updates the |
62 | | * inline frame and span data to account for any change in positions |
63 | | * due to available space for the line boxes changing. |
64 | | * @param aX/aY/aWidth/aHeight are the new available |
65 | | * space rectangle, relative to the containing block. |
66 | | * @param aFloatFrame the float frame that was placed. |
67 | | */ |
68 | | void UpdateBand(mozilla::WritingMode aWM, |
69 | | const mozilla::LogicalRect& aNewAvailableSpace, |
70 | | nsIFrame* aFloatFrame); |
71 | | |
72 | | void BeginSpan(nsIFrame* aFrame, const ReflowInput* aSpanReflowInput, |
73 | | nscoord aLeftEdge, nscoord aRightEdge, nscoord* aBaseline); |
74 | | |
75 | | // Returns the width of the span |
76 | | nscoord EndSpan(nsIFrame* aFrame); |
77 | | |
78 | | // This method attaches the last frame reflowed in this line layout |
79 | | // to that in the base line layout. |
80 | | void AttachLastFrameToBaseLineLayout() |
81 | 0 | { |
82 | 0 | AttachFrameToBaseLineLayout(LastFrame()); |
83 | 0 | } |
84 | | |
85 | | // This method attaches the root frame of this line layout to the |
86 | | // last reflowed frame in the base line layout. |
87 | | void AttachRootFrameToBaseLineLayout() |
88 | 0 | { |
89 | 0 | AttachFrameToBaseLineLayout(mRootSpan->mFrame); |
90 | 0 | } |
91 | | |
92 | | int32_t GetCurrentSpanCount() const; |
93 | | |
94 | | void SplitLineTo(int32_t aNewCount); |
95 | | |
96 | | bool IsZeroBSize(); |
97 | | |
98 | | // Reflows the frame and returns the reflow status. aPushedFrame is true |
99 | | // if the frame is pushed to the next line because it doesn't fit. |
100 | | void ReflowFrame(nsIFrame* aFrame, |
101 | | nsReflowStatus& aReflowStatus, |
102 | | ReflowOutput* aMetrics, |
103 | | bool& aPushedFrame); |
104 | | |
105 | | void AddBulletFrame(nsBulletFrame* aFrame, const ReflowOutput& aMetrics); |
106 | | |
107 | | void RemoveBulletFrame(nsBulletFrame* aFrame); |
108 | | |
109 | | /** |
110 | | * Place frames in the block direction (CSS property vertical-align) |
111 | | */ |
112 | | void VerticalAlignLine(); |
113 | | |
114 | | bool TrimTrailingWhiteSpace(); |
115 | | |
116 | | /** |
117 | | * Place frames in the inline direction (CSS property text-align). |
118 | | */ |
119 | | void TextAlignLine(nsLineBox* aLine, bool aIsLastLine); |
120 | | |
121 | | /** |
122 | | * Handle all the relative positioning in the line, compute the |
123 | | * combined area (== overflow area) for the line, and handle view |
124 | | * sizing/positioning and the setting of the overflow rect. |
125 | | */ |
126 | | void RelativePositionFrames(nsOverflowAreas& aOverflowAreas) |
127 | 0 | { |
128 | 0 | RelativePositionFrames(mRootSpan, aOverflowAreas); |
129 | 0 | } |
130 | | |
131 | | // Support methods for word-wrapping during line reflow |
132 | | |
133 | | void SetJustificationInfo(const mozilla::JustificationInfo& aInfo) |
134 | 0 | { |
135 | 0 | mJustificationInfo = aInfo; |
136 | 0 | } |
137 | | |
138 | | /** |
139 | | * @return true if so far during reflow no non-empty content has been |
140 | | * placed in the line (according to nsIFrame::IsEmpty()) |
141 | | */ |
142 | | bool LineIsEmpty() const |
143 | 0 | { |
144 | 0 | return mLineIsEmpty; |
145 | 0 | } |
146 | | |
147 | | /** |
148 | | * @return true if so far during reflow no non-empty leaf content |
149 | | * (non-collapsed whitespace, replaced element, inline-block, etc) has been |
150 | | * placed in the line |
151 | | */ |
152 | | bool LineAtStart() const |
153 | 0 | { |
154 | 0 | return mLineAtStart; |
155 | 0 | } |
156 | | |
157 | | bool LineIsBreakable() const; |
158 | | |
159 | | bool GetLineEndsInBR() const |
160 | 0 | { |
161 | 0 | return mLineEndsInBR; |
162 | 0 | } |
163 | | |
164 | | void SetLineEndsInBR(bool aOn) |
165 | 0 | { |
166 | 0 | mLineEndsInBR = aOn; |
167 | 0 | } |
168 | | |
169 | | //---------------------------------------- |
170 | | // Inform the line-layout about the presence of a floating frame |
171 | | // XXX get rid of this: use get-frame-type? |
172 | | bool AddFloat(nsIFrame* aFloat, nscoord aAvailableISize) |
173 | 0 | { |
174 | 0 | // When reflowing ruby text frames, no block reflow state is |
175 | 0 | // provided to the line layout. However, floats should never be |
176 | 0 | // associated with ruby text containers, hence this method should |
177 | 0 | // not be called in that case. |
178 | 0 | MOZ_ASSERT(mBlockRI, |
179 | 0 | "Should not call this method if there is no block reflow state " |
180 | 0 | "available"); |
181 | 0 | return mBlockRI->AddFloat(this, aFloat, aAvailableISize); |
182 | 0 | } |
183 | | |
184 | 0 | void SetTrimmableISize(nscoord aTrimmableISize) { |
185 | 0 | mTrimmableISize = aTrimmableISize; |
186 | 0 | } |
187 | | |
188 | | //---------------------------------------- |
189 | | |
190 | 0 | bool GetFirstLetterStyleOK() const { |
191 | 0 | return mFirstLetterStyleOK; |
192 | 0 | } |
193 | | |
194 | 0 | void SetFirstLetterStyleOK(bool aSetting) { |
195 | 0 | mFirstLetterStyleOK = aSetting; |
196 | 0 | } |
197 | | |
198 | 0 | bool GetInFirstLetter() const { |
199 | 0 | return mInFirstLetter; |
200 | 0 | } |
201 | | |
202 | 0 | void SetInFirstLetter(bool aSetting) { |
203 | 0 | mInFirstLetter = aSetting; |
204 | 0 | } |
205 | | |
206 | 0 | bool GetInFirstLine() const { |
207 | 0 | return mInFirstLine; |
208 | 0 | } |
209 | | |
210 | 0 | void SetInFirstLine(bool aSetting) { |
211 | 0 | mInFirstLine = aSetting; |
212 | 0 | } |
213 | | |
214 | | // Calling this during block reflow ensures that the next line of inlines |
215 | | // will be marked dirty, if there is one. |
216 | 0 | void SetDirtyNextLine() { |
217 | 0 | mDirtyNextLine = true; |
218 | 0 | } |
219 | 0 | bool GetDirtyNextLine() { |
220 | 0 | return mDirtyNextLine; |
221 | 0 | } |
222 | | |
223 | | //---------------------------------------- |
224 | | |
225 | | nsPresContext* mPresContext; |
226 | | |
227 | | /** |
228 | | * Record where an optional break could have been placed. During line reflow, |
229 | | * frames containing optional break points (e.g., whitespace in text frames) |
230 | | * can call SetLastOptionalBreakPosition to record where a break could |
231 | | * have been made, but wasn't because we decided to place more content on |
232 | | * the line. For non-text frames, offset 0 means before the frame, offset |
233 | | * INT32_MAX means after the frame. |
234 | | * |
235 | | * Currently this is used to handle cases where a single word comprises |
236 | | * multiple frames, and the first frame fits on the line but the whole word |
237 | | * doesn't. We look back to the last optional break position and |
238 | | * reflow the whole line again, forcing a break at that position. The last |
239 | | * optional break position could be in a text frame or else after a frame |
240 | | * that cannot be part of a text run, so those are the positions we record. |
241 | | * |
242 | | * @param aFrame the frame which contains the optional break position. |
243 | | * |
244 | | * @param aFits set to true if the break position is within the available width. |
245 | | * |
246 | | * @param aPriority the priority of the break opportunity. If we are |
247 | | * prioritizing break opportunities, we will not set a break if we have |
248 | | * already set a break with a higher priority. @see gfxBreakPriority. |
249 | | * |
250 | | * @return true if we are actually reflowing with forced break position and we |
251 | | * should break here |
252 | | */ |
253 | | bool NotifyOptionalBreakPosition(nsIFrame* aFrame, |
254 | | int32_t aOffset, |
255 | | bool aFits, |
256 | | gfxBreakPriority aPriority); |
257 | | |
258 | | // Tries to place a float, and records whether the float actually was placed. |
259 | | bool TryToPlaceFloat(nsIFrame* aFloat); |
260 | | |
261 | | // Records a floating frame in a nowrap context for it to be placed on the |
262 | | // next break opportunity. |
263 | | void RecordNoWrapFloat(nsIFrame* aFloat); |
264 | | |
265 | | // Tries to place the floats from the nowrap context. |
266 | | void FlushNoWrapFloats(); |
267 | | |
268 | | /** |
269 | | * Like NotifyOptionalBreakPosition, but here it's OK for mNeedBackup |
270 | | * to be set, because the caller is merely pruning some saved break position(s) |
271 | | * that are actually not feasible. |
272 | | */ |
273 | | void RestoreSavedBreakPosition(nsIFrame* aFrame, int32_t aOffset, |
274 | 0 | gfxBreakPriority aPriority) { |
275 | 0 | mLastOptionalBreakFrame = aFrame; |
276 | 0 | mLastOptionalBreakFrameOffset = aOffset; |
277 | 0 | mLastOptionalBreakPriority = aPriority; |
278 | 0 | } |
279 | | /** |
280 | | * Signal that no backing up will be required after all. |
281 | | */ |
282 | 0 | void ClearOptionalBreakPosition() { |
283 | 0 | mNeedBackup = false; |
284 | 0 | mLastOptionalBreakFrame = nullptr; |
285 | 0 | mLastOptionalBreakFrameOffset = -1; |
286 | 0 | mLastOptionalBreakPriority = gfxBreakPriority::eNoBreak; |
287 | 0 | } |
288 | | // Retrieve last set optional break position. When this returns null, no |
289 | | // optional break has been recorded (which means that the line can't break yet). |
290 | | nsIFrame* GetLastOptionalBreakPosition(int32_t* aOffset, |
291 | 0 | gfxBreakPriority* aPriority) { |
292 | 0 | *aOffset = mLastOptionalBreakFrameOffset; |
293 | 0 | *aPriority = mLastOptionalBreakPriority; |
294 | 0 | return mLastOptionalBreakFrame; |
295 | 0 | } |
296 | | // Whether any optional break position has been recorded. |
297 | | bool HasOptionalBreakPosition() const |
298 | 0 | { |
299 | 0 | return mLastOptionalBreakFrame != nullptr; |
300 | 0 | } |
301 | | // Get the priority of the last optional break position recorded. |
302 | | gfxBreakPriority LastOptionalBreakPriority() const |
303 | 0 | { |
304 | 0 | return mLastOptionalBreakPriority; |
305 | 0 | } |
306 | | |
307 | | /** |
308 | | * Check whether frames overflowed the available width and CanPlaceFrame |
309 | | * requested backing up to a saved break position. |
310 | | */ |
311 | 0 | bool NeedsBackup() { return mNeedBackup; } |
312 | | |
313 | | // Line layout may place too much content on a line, overflowing its available |
314 | | // width. When that happens, if SetLastOptionalBreakPosition has been |
315 | | // used to record an optional break that wasn't taken, we can reflow the line |
316 | | // again and force the break to happen at that point (i.e., backtracking |
317 | | // to the last choice point). |
318 | | |
319 | | // Record that we want to break at the given content+offset (which |
320 | | // should have been previously returned by GetLastOptionalBreakPosition |
321 | | // from another nsLineLayout). |
322 | 0 | void ForceBreakAtPosition(nsIFrame* aFrame, int32_t aOffset) { |
323 | 0 | mForceBreakFrame = aFrame; |
324 | 0 | mForceBreakFrameOffset = aOffset; |
325 | 0 | } |
326 | 0 | bool HaveForcedBreakPosition() { return mForceBreakFrame != nullptr; } |
327 | 0 | int32_t GetForcedBreakPosition(nsIFrame* aFrame) { |
328 | 0 | return mForceBreakFrame == aFrame ? mForceBreakFrameOffset : -1; |
329 | 0 | } |
330 | | |
331 | | /** |
332 | | * This can't be null. It usually returns a block frame but may return |
333 | | * some other kind of frame when inline frames are reflowed in a non-block |
334 | | * context (e.g. MathML or floating first-letter). |
335 | | */ |
336 | 0 | nsIFrame* LineContainerFrame() const { return mBlockReflowInput->mFrame; } |
337 | 0 | const ReflowInput* LineContainerRI() const { return mBlockReflowInput; } |
338 | 0 | const nsLineList::iterator* GetLine() const { |
339 | 0 | return mGotLineBox ? &mLineBox : nullptr; |
340 | 0 | } |
341 | 0 | nsLineList::iterator* GetLine() { |
342 | 0 | return mGotLineBox ? &mLineBox : nullptr; |
343 | 0 | } |
344 | | |
345 | | /** |
346 | | * Returns the accumulated advance width of frames before the current frame |
347 | | * on the line, plus the line container's left border+padding. |
348 | | * This is always positive, the advance width is measured from |
349 | | * the right edge for RTL blocks and from the left edge for LTR blocks. |
350 | | * In other words, the current frame's distance from the line container's |
351 | | * start content edge is: |
352 | | * <code>GetCurrentFrameInlineDistanceFromBlock() - lineContainer->GetUsedBorderAndPadding().left</code> |
353 | | * Note the use of <code>.left</code> for both LTR and RTL line containers. |
354 | | */ |
355 | | nscoord GetCurrentFrameInlineDistanceFromBlock(); |
356 | | |
357 | | /** |
358 | | * Move the inline position where the next frame will be reflowed forward by |
359 | | * aAmount. |
360 | | */ |
361 | 0 | void AdvanceICoord(nscoord aAmount) { mCurrentSpan->mICoord += aAmount; } |
362 | | /** |
363 | | * Returns the writing mode for the root span. |
364 | | */ |
365 | 0 | mozilla::WritingMode GetWritingMode() { return mRootSpan->mWritingMode; } |
366 | | /** |
367 | | * Returns the inline position where the next frame will be reflowed. |
368 | | */ |
369 | 0 | nscoord GetCurrentICoord() { return mCurrentSpan->mICoord; } |
370 | | |
371 | 0 | void SetSuppressLineWrap(bool aEnabled) { mSuppressLineWrap = aEnabled; } |
372 | | |
373 | | protected: |
374 | | // This state is constant for a given block frame doing line layout |
375 | | |
376 | | // A non-owning pointer, which points to the object owned by |
377 | | // nsAutoFloatManager::mNew. |
378 | | nsFloatManager* mFloatManager; |
379 | | |
380 | | const nsStyleText* mStyleText; // for the block |
381 | | const ReflowInput* mBlockReflowInput; |
382 | | |
383 | | // The line layout for the base text. It is usually nullptr. |
384 | | // It becomes not null when the current line layout is for ruby |
385 | | // annotations. When there is nested ruby inside annotation, it |
386 | | // forms a linked list from the inner annotation to the outermost |
387 | | // line layout. The outermost line layout, which has this member |
388 | | // being nullptr, is responsible for managing the life cycle of |
389 | | // per-frame data and per-span data, and handling floats. |
390 | | nsLineLayout* const mBaseLineLayout; |
391 | | |
392 | 0 | nsLineLayout* GetOutermostLineLayout() { |
393 | 0 | nsLineLayout* lineLayout = this; |
394 | 0 | while (lineLayout->mBaseLineLayout) { |
395 | 0 | lineLayout = lineLayout->mBaseLineLayout; |
396 | 0 | } |
397 | 0 | return lineLayout; |
398 | 0 | } |
399 | | |
400 | | nsIFrame* mLastOptionalBreakFrame; |
401 | | nsIFrame* mForceBreakFrame; |
402 | | |
403 | | // XXX remove this when landing bug 154892 (splitting absolute positioned frames) |
404 | | friend class nsInlineFrame; |
405 | | |
406 | | // XXX Take care that nsRubyBaseContainer would give nullptr to this |
407 | | // member. It should not be a problem currently, since the only |
408 | | // code use it is handling float, which does not affect ruby. |
409 | | // See comment in nsLineLayout::AddFloat |
410 | | BlockReflowInput* mBlockRI;/* XXX hack! */ |
411 | | |
412 | | nsLineList::iterator mLineBox; |
413 | | |
414 | | // Per-frame data recorded by the line-layout reflow logic. This |
415 | | // state is the state needed to post-process the line after reflow |
416 | | // has completed (block-direction alignment, inline-direction alignment, |
417 | | // justification and relative positioning). |
418 | | |
419 | | struct PerSpanData; |
420 | | struct PerFrameData; |
421 | | friend struct PerSpanData; |
422 | | friend struct PerFrameData; |
423 | | struct PerFrameData |
424 | | { |
425 | | // link to next/prev frame in same span |
426 | | PerFrameData* mNext; |
427 | | PerFrameData* mPrev; |
428 | | |
429 | | // Link to the frame of next ruby annotation. It is a linked list |
430 | | // through this pointer from ruby base to all its annotations. It |
431 | | // could be nullptr if there is no more annotation. |
432 | | // If PFD_ISLINKEDTOBASE is set, the current PFD is one of the ruby |
433 | | // annotations in the base's list, otherwise it is the ruby base, |
434 | | // and its mNextAnnotation is the start of the linked list. |
435 | | PerFrameData* mNextAnnotation; |
436 | | |
437 | | // pointer to child span data if this is an inline container frame |
438 | | PerSpanData* mSpan; |
439 | | |
440 | | // The frame |
441 | | nsIFrame* mFrame; |
442 | | |
443 | | // From metrics |
444 | | nscoord mAscent; |
445 | | // note that mBounds is a logical rect in the *line*'s writing mode. |
446 | | // When setting frame coordinates, we have to convert to the frame's |
447 | | // writing mode |
448 | | mozilla::LogicalRect mBounds; |
449 | | nsOverflowAreas mOverflowAreas; |
450 | | |
451 | | // From reflow-state |
452 | | mozilla::LogicalMargin mMargin; // in *line* writing mode |
453 | | mozilla::LogicalMargin mBorderPadding; // in *line* writing mode |
454 | | mozilla::LogicalMargin mOffsets; // in *frame* writing mode |
455 | | |
456 | | // state for text justification |
457 | | // Note that, although all frames would have correct inner |
458 | | // opportunities computed after ComputeFrameJustification, start |
459 | | // and end justifiable info are not reliable for non-text frames. |
460 | | mozilla::JustificationInfo mJustificationInfo; |
461 | | mozilla::JustificationAssignment mJustificationAssignment; |
462 | | |
463 | | // PerFrameData flags |
464 | | bool mRelativePos : 1; |
465 | | bool mIsTextFrame : 1; |
466 | | bool mIsNonEmptyTextFrame : 1; |
467 | | bool mIsNonWhitespaceTextFrame : 1; |
468 | | bool mIsLetterFrame : 1; |
469 | | bool mRecomputeOverflow : 1; |
470 | | bool mIsBullet : 1; |
471 | | bool mSkipWhenTrimmingWhitespace : 1; |
472 | | bool mIsEmpty : 1; |
473 | | bool mIsPlaceholder : 1; |
474 | | bool mIsLinkedToBase : 1; |
475 | | |
476 | | // Other state we use |
477 | | uint8_t mBlockDirAlign; |
478 | | mozilla::WritingMode mWritingMode; |
479 | | |
480 | 0 | PerFrameData* Last() { |
481 | 0 | PerFrameData* pfd = this; |
482 | 0 | while (pfd->mNext) { |
483 | 0 | pfd = pfd->mNext; |
484 | 0 | } |
485 | 0 | return pfd; |
486 | 0 | } |
487 | | |
488 | | bool IsStartJustifiable() const |
489 | 0 | { |
490 | 0 | return mJustificationInfo.mIsStartJustifiable; |
491 | 0 | } |
492 | | |
493 | | bool IsEndJustifiable() const |
494 | 0 | { |
495 | 0 | return mJustificationInfo.mIsEndJustifiable; |
496 | 0 | } |
497 | | |
498 | | bool ParticipatesInJustification() const; |
499 | | }; |
500 | | PerFrameData* mFrameFreeList; |
501 | | |
502 | | // In nsLineLayout, a "span" is a container inline frame, and a "frame" is one |
503 | | // of its children. |
504 | | // |
505 | | // nsLineLayout::BeginLineReflow() creates the initial PerSpanData which is |
506 | | // called the "root span". nsInlineFrame::ReflowFrames() creates a new |
507 | | // PerSpanData when it calls nsLineLayout::BeginSpan(); at this time, the |
508 | | // nsLineLayout object's mCurrentSpan is switched to the new span. The new |
509 | | // span records the old mCurrentSpan as its parent. After reflowing the child |
510 | | // inline frames, nsInlineFrame::ReflowFrames() calls nsLineLayout::EndSpan(), |
511 | | // which pops the PerSpanData and re-sets mCurrentSpan. |
512 | | struct PerSpanData { |
513 | | union { |
514 | | PerSpanData* mParent; |
515 | | PerSpanData* mNextFreeSpan; |
516 | | }; |
517 | | |
518 | | // The PerFrameData of the inline frame that "owns" the span, or null if |
519 | | // this is the root span. mFrame is initialized to the containing inline |
520 | | // frame's PerFrameData when a new PerSpanData is pushed in |
521 | | // nsLineLayout::BeginSpan(). |
522 | | PerFrameData* mFrame; |
523 | | |
524 | | // The first PerFrameData structure in the span. |
525 | | PerFrameData* mFirstFrame; |
526 | | |
527 | | // The last PerFrameData structure in the span. PerFrameData structures are |
528 | | // added to the span as they are reflowed. mLastFrame may also be directly |
529 | | // manipulated if a line is split, or if frames are pushed from one line to |
530 | | // the next. |
531 | | PerFrameData* mLastFrame; |
532 | | |
533 | | const ReflowInput* mReflowInput; |
534 | | bool mNoWrap; |
535 | | mozilla::WritingMode mWritingMode; |
536 | | bool mContainsFloat; |
537 | | bool mHasNonemptyContent; |
538 | | |
539 | | nscoord mIStart; |
540 | | nscoord mICoord; |
541 | | nscoord mIEnd; |
542 | | |
543 | | nscoord mBStartLeading, mBEndLeading; |
544 | | nscoord mLogicalBSize; |
545 | | nscoord mMinBCoord, mMaxBCoord; |
546 | | nscoord* mBaseline; |
547 | | |
548 | 0 | void AppendFrame(PerFrameData* pfd) { |
549 | 0 | if (!mLastFrame) { |
550 | 0 | mFirstFrame = pfd; |
551 | 0 | } else { |
552 | 0 | mLastFrame->mNext = pfd; |
553 | 0 | pfd->mPrev = mLastFrame; |
554 | 0 | } |
555 | 0 | mLastFrame = pfd; |
556 | 0 | } |
557 | | }; |
558 | | PerSpanData* mSpanFreeList; |
559 | | PerSpanData* mRootSpan; |
560 | | PerSpanData* mCurrentSpan; |
561 | | |
562 | | // The container size to use when converting between logical and |
563 | | // physical coordinates for frames in this span. For the root span |
564 | | // this is the size of the block cached in mContainerSize; for |
565 | | // child spans it's the size of the root span. |
566 | 0 | nsSize ContainerSizeForSpan(PerSpanData* aPSD) { |
567 | 0 | return (aPSD == mRootSpan) |
568 | 0 | ? mContainerSize |
569 | 0 | : aPSD->mFrame->mBounds.Size(mRootSpan->mWritingMode). |
570 | 0 | GetPhysicalSize(mRootSpan->mWritingMode); |
571 | 0 | } |
572 | | |
573 | | gfxBreakPriority mLastOptionalBreakPriority; |
574 | | int32_t mLastOptionalBreakFrameOffset; |
575 | | int32_t mForceBreakFrameOffset; |
576 | | |
577 | | nscoord mMinLineBSize; |
578 | | |
579 | | // The amount of text indent that we applied to this line, needed for |
580 | | // max-element-size calculation. |
581 | | nscoord mTextIndent; |
582 | | |
583 | | // This state varies during the reflow of a line but is line |
584 | | // "global" state not span "local" state. |
585 | | int32_t mLineNumber; |
586 | | mozilla::JustificationInfo mJustificationInfo; |
587 | | |
588 | | int32_t mTotalPlacedFrames; |
589 | | |
590 | | nscoord mBStartEdge; |
591 | | nscoord mMaxStartBoxBSize; |
592 | | nscoord mMaxEndBoxBSize; |
593 | | |
594 | | nscoord mInflationMinFontSize; |
595 | | |
596 | | // Final computed line-bSize value after VerticalAlignFrames for |
597 | | // the block has been called. |
598 | | nscoord mFinalLineBSize; |
599 | | |
600 | | // Amount of trimmable whitespace inline size for the trailing text |
601 | | // frame, if any |
602 | | nscoord mTrimmableISize; |
603 | | |
604 | | // Physical size. Use only for physical <-> logical coordinate conversion. |
605 | | nsSize mContainerSize; |
606 | 0 | const nsSize& ContainerSize() const { return mContainerSize; } |
607 | | |
608 | | bool mFirstLetterStyleOK : 1; |
609 | | bool mIsTopOfPage : 1; |
610 | | bool mImpactedByFloats : 1; |
611 | | bool mLastFloatWasLetterFrame : 1; |
612 | | bool mLineIsEmpty : 1; |
613 | | bool mLineEndsInBR : 1; |
614 | | bool mNeedBackup : 1; |
615 | | bool mInFirstLine : 1; |
616 | | bool mGotLineBox : 1; |
617 | | bool mInFirstLetter : 1; |
618 | | bool mHasBullet : 1; |
619 | | bool mDirtyNextLine : 1; |
620 | | bool mLineAtStart : 1; |
621 | | bool mHasRuby : 1; |
622 | | bool mSuppressLineWrap : 1; |
623 | | |
624 | | int32_t mSpanDepth; |
625 | | #ifdef DEBUG |
626 | | int32_t mSpansAllocated, mSpansFreed; |
627 | | int32_t mFramesAllocated, mFramesFreed; |
628 | | #endif |
629 | | |
630 | | /** |
631 | | * Per span and per frame data. |
632 | | */ |
633 | | mozilla::ArenaAllocator<1024, sizeof(void*)> mArena; |
634 | | |
635 | | /** |
636 | | * Allocate a PerFrameData from the mArena pool. The allocation is infallible. |
637 | | */ |
638 | | PerFrameData* NewPerFrameData(nsIFrame* aFrame); |
639 | | |
640 | | /** |
641 | | * Allocate a PerSpanData from the mArena pool. The allocation is infallible. |
642 | | */ |
643 | | PerSpanData* NewPerSpanData(); |
644 | | |
645 | 0 | PerFrameData* LastFrame() const { return mCurrentSpan->mLastFrame; } |
646 | | |
647 | | /** |
648 | | * Unlink the given PerFrameData and all the siblings after it from |
649 | | * the span. The unlinked PFDs are usually freed immediately. |
650 | | * However, if PFD_ISLINKEDTOBASE is set, it won't be freed until |
651 | | * the frame of its base is unlinked. |
652 | | */ |
653 | | void UnlinkFrame(PerFrameData* pfd); |
654 | | |
655 | | /** |
656 | | * Free the given PerFrameData. |
657 | | */ |
658 | | void FreeFrame(PerFrameData* pfd); |
659 | | |
660 | | void FreeSpan(PerSpanData* psd); |
661 | | |
662 | 0 | bool InBlockContext() const { |
663 | 0 | return mSpanDepth == 0; |
664 | 0 | } |
665 | | |
666 | | void PushFrame(nsIFrame* aFrame); |
667 | | |
668 | | void AllowForStartMargin(PerFrameData* pfd, |
669 | | ReflowInput& aReflowInput); |
670 | | |
671 | | void SyncAnnotationBounds(PerFrameData* aRubyFrame); |
672 | | |
673 | | bool CanPlaceFrame(PerFrameData* pfd, |
674 | | bool aNotSafeToBreak, |
675 | | bool aFrameCanContinueTextRun, |
676 | | bool aCanRollBackBeforeFrame, |
677 | | ReflowOutput& aMetrics, |
678 | | nsReflowStatus& aStatus, |
679 | | bool* aOptionalBreakAfterFits); |
680 | | |
681 | | void PlaceFrame(PerFrameData* pfd, |
682 | | ReflowOutput& aMetrics); |
683 | | |
684 | | void AdjustLeadings(nsIFrame* spanFrame, PerSpanData* psd, |
685 | | const nsStyleText* aStyleText, float aInflation, |
686 | | bool* aZeroEffectiveSpanBox); |
687 | | |
688 | | void VerticalAlignFrames(PerSpanData* psd); |
689 | | |
690 | | void PlaceTopBottomFrames(PerSpanData* psd, |
691 | | nscoord aDistanceFromStart, |
692 | | nscoord aLineBSize); |
693 | | |
694 | | void ApplyRelativePositioning(PerFrameData* aPFD); |
695 | | |
696 | | void RelativePositionAnnotations(PerSpanData* aRubyPSD, |
697 | | nsOverflowAreas& aOverflowAreas); |
698 | | |
699 | | void RelativePositionFrames(PerSpanData* psd, nsOverflowAreas& aOverflowAreas); |
700 | | |
701 | | bool TrimTrailingWhiteSpaceIn(PerSpanData* psd, nscoord* aDeltaISize); |
702 | | |
703 | | struct JustificationComputationState; |
704 | | |
705 | | static int AssignInterframeJustificationGaps( |
706 | | PerFrameData* aFrame, JustificationComputationState& aState); |
707 | | |
708 | | int32_t ComputeFrameJustification(PerSpanData* psd, |
709 | | JustificationComputationState& aState); |
710 | | |
711 | | void AdvanceAnnotationInlineBounds(PerFrameData* aPFD, |
712 | | const nsSize& aContainerSize, |
713 | | nscoord aDeltaICoord, |
714 | | nscoord aDeltaISize); |
715 | | |
716 | | void ApplyLineJustificationToAnnotations(PerFrameData* aPFD, |
717 | | nscoord aDeltaICoord, |
718 | | nscoord aDeltaISize); |
719 | | |
720 | | // Apply justification. The return value is the amount by which the width of |
721 | | // the span corresponding to aPSD got increased due to justification. |
722 | | nscoord ApplyFrameJustification( |
723 | | PerSpanData* aPSD, mozilla::JustificationApplicationState& aState); |
724 | | |
725 | | void ExpandRubyBox(PerFrameData* aFrame, nscoord aReservedISize, |
726 | | const nsSize& aContainerSize); |
727 | | |
728 | | void ExpandRubyBoxWithAnnotations(PerFrameData* aFrame, |
729 | | const nsSize& aContainerSize); |
730 | | |
731 | | void ExpandInlineRubyBoxes(PerSpanData* aSpan); |
732 | | |
733 | | void AttachFrameToBaseLineLayout(PerFrameData* aFrame); |
734 | | |
735 | | #ifdef DEBUG |
736 | | void DumpPerSpanData(PerSpanData* psd, int32_t aIndent); |
737 | | #endif |
738 | | }; |
739 | | |
740 | | #endif /* nsLineLayout_h___ */ |