Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : // vim:cindent:ts=2:et:sw=2:
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 : /* representation of one line within a block frame, a CSS line box */
8 :
9 : #ifndef nsLineBox_h___
10 : #define nsLineBox_h___
11 :
12 : #include "mozilla/Attributes.h"
13 : #include "mozilla/Likely.h"
14 :
15 : #include "nsILineIterator.h"
16 : #include "nsIFrame.h"
17 : #include <algorithm>
18 :
19 : class nsLineBox;
20 : class nsFloatCache;
21 : class nsFloatCacheList;
22 : class nsFloatCacheFreeList;
23 :
24 : // State cached after reflowing a float. This state is used during
25 : // incremental reflow when we avoid reflowing a float.
26 : class nsFloatCache {
27 : public:
28 : nsFloatCache();
29 : #ifdef NS_BUILD_REFCNT_LOGGING
30 : ~nsFloatCache();
31 : #else
32 : ~nsFloatCache() { }
33 : #endif
34 :
35 0 : nsFloatCache* Next() const { return mNext; }
36 :
37 : nsIFrame* mFloat; // floating frame
38 :
39 : protected:
40 : nsFloatCache* mNext;
41 :
42 : friend class nsFloatCacheList;
43 : friend class nsFloatCacheFreeList;
44 : };
45 :
46 : //----------------------------------------
47 :
48 : class nsFloatCacheList {
49 : public:
50 : #ifdef NS_BUILD_REFCNT_LOGGING
51 : nsFloatCacheList();
52 : #else
53 : nsFloatCacheList() : mHead(nullptr) { }
54 : #endif
55 : ~nsFloatCacheList();
56 :
57 0 : bool IsEmpty() const {
58 0 : return nullptr == mHead;
59 : }
60 :
61 158 : bool NotEmpty() const {
62 158 : return nullptr != mHead;
63 : }
64 :
65 0 : nsFloatCache* Head() const {
66 0 : return mHead;
67 : }
68 :
69 : nsFloatCache* Tail() const;
70 :
71 : void DeleteAll();
72 :
73 : nsFloatCache* Find(nsIFrame* aOutOfFlowFrame);
74 :
75 : // Remove a nsFloatCache from this list. Deleting this nsFloatCache
76 : // becomes the caller's responsibility.
77 0 : void Remove(nsFloatCache* aElement) { RemoveAndReturnPrev(aElement); }
78 :
79 : // Steal away aList's nsFloatCache objects and put them in this
80 : // list. aList must not be empty.
81 : void Append(nsFloatCacheFreeList& aList);
82 :
83 : protected:
84 : nsFloatCache* mHead;
85 :
86 : // Remove a nsFloatCache from this list. Deleting this nsFloatCache
87 : // becomes the caller's responsibility. Returns the nsFloatCache that was
88 : // before aElement, or nullptr if aElement was the first.
89 : nsFloatCache* RemoveAndReturnPrev(nsFloatCache* aElement);
90 :
91 : friend class nsFloatCacheFreeList;
92 : };
93 :
94 : //---------------------------------------
95 : // Like nsFloatCacheList, but with fast access to the tail
96 :
97 : class nsFloatCacheFreeList : private nsFloatCacheList {
98 : public:
99 : #ifdef NS_BUILD_REFCNT_LOGGING
100 : nsFloatCacheFreeList();
101 : ~nsFloatCacheFreeList();
102 : #else
103 : nsFloatCacheFreeList() : mTail(nullptr) { }
104 : ~nsFloatCacheFreeList() { }
105 : #endif
106 :
107 : // Reimplement trivial functions
108 0 : bool IsEmpty() const {
109 0 : return nullptr == mHead;
110 : }
111 :
112 0 : nsFloatCache* Head() const {
113 0 : return mHead;
114 : }
115 :
116 0 : nsFloatCache* Tail() const {
117 0 : return mTail;
118 : }
119 :
120 150 : bool NotEmpty() const {
121 150 : return nullptr != mHead;
122 : }
123 :
124 : void DeleteAll();
125 :
126 : // Steal away aList's nsFloatCache objects and put them on this
127 : // free-list. aList must not be empty.
128 : void Append(nsFloatCacheList& aList);
129 :
130 : void Append(nsFloatCache* aFloatCache);
131 :
132 : void Remove(nsFloatCache* aElement);
133 :
134 : // Remove an nsFloatCache object from this list and return it, or create
135 : // a new one if this one is empty; Set its mFloat to aFloat.
136 : nsFloatCache* Alloc(nsIFrame* aFloat);
137 :
138 : protected:
139 : nsFloatCache* mTail;
140 :
141 : friend class nsFloatCacheList;
142 : };
143 :
144 : //----------------------------------------------------------------------
145 :
146 : #define LINE_MAX_CHILD_COUNT INT32_MAX
147 :
148 : /**
149 : * Function to create a line box and initialize it with a single frame.
150 : * The allocation is infallible.
151 : * If the frame was moved from another line then you're responsible
152 : * for notifying that line using NoteFrameRemoved(). Alternatively,
153 : * it's better to use the next function that does that for you in an
154 : * optimal way.
155 : */
156 : nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
157 : bool aIsBlock);
158 : /**
159 : * Function to create a line box and initialize it with aCount frames
160 : * that are currently on aFromLine. The allocation is infallible.
161 : */
162 : nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine,
163 : nsIFrame* aFrame, int32_t aCount);
164 :
165 : class nsLineList;
166 :
167 : // don't use the following names outside of this file. Instead, use
168 : // nsLineList::iterator, etc. These are just here to allow them to
169 : // be specified as parameters to methods of nsLineBox.
170 : class nsLineList_iterator;
171 : class nsLineList_const_iterator;
172 : class nsLineList_reverse_iterator;
173 : class nsLineList_const_reverse_iterator;
174 :
175 : /**
176 : * Users must have the class that is to be part of the list inherit
177 : * from nsLineLink. If they want to be efficient, it should be the
178 : * first base class. (This was originally nsCLink in a templatized
179 : * nsCList, but it's still useful separately.)
180 : */
181 :
182 33 : class nsLineLink {
183 :
184 : public:
185 : friend class nsLineList;
186 : friend class nsLineList_iterator;
187 : friend class nsLineList_reverse_iterator;
188 : friend class nsLineList_const_iterator;
189 : friend class nsLineList_const_reverse_iterator;
190 :
191 : private:
192 : nsLineLink *_mNext; // or head
193 : nsLineLink *_mPrev; // or tail
194 :
195 : };
196 :
197 :
198 : /**
199 : * The nsLineBox class represents a horizontal line of frames. It contains
200 : * enough state to support incremental reflow of the frames, event handling
201 : * for the frames, and rendering of the frames.
202 : */
203 : class nsLineBox final : public nsLineLink {
204 : private:
205 : nsLineBox(nsIFrame* aFrame, int32_t aCount, bool aIsBlock);
206 : ~nsLineBox();
207 :
208 : // Infallible overloaded new operator. Uses an arena (which comes from the
209 : // presShell) to perform the allocation.
210 : void* operator new(size_t sz, nsIPresShell* aPresShell);
211 : void operator delete(void* aPtr, size_t sz) = delete;
212 :
213 : public:
214 : // Use these functions to allocate and destroy line boxes
215 : friend nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsIFrame* aFrame,
216 : bool aIsBlock);
217 : friend nsLineBox* NS_NewLineBox(nsIPresShell* aPresShell, nsLineBox* aFromLine,
218 : nsIFrame* aFrame, int32_t aCount);
219 : void Destroy(nsIPresShell* aPresShell);
220 :
221 : // mBlock bit
222 1654 : bool IsBlock() const {
223 1654 : return mFlags.mBlock;
224 : }
225 1077 : bool IsInline() const {
226 1077 : return !mFlags.mBlock;
227 : }
228 :
229 : // mDirty bit
230 149 : void MarkDirty() {
231 149 : mFlags.mDirty = 1;
232 149 : }
233 85 : void ClearDirty() {
234 85 : mFlags.mDirty = 0;
235 85 : }
236 972 : bool IsDirty() const {
237 972 : return mFlags.mDirty;
238 : }
239 :
240 : // mPreviousMarginDirty bit
241 0 : void MarkPreviousMarginDirty() {
242 0 : mFlags.mPreviousMarginDirty = 1;
243 0 : }
244 0 : void ClearPreviousMarginDirty() {
245 0 : mFlags.mPreviousMarginDirty = 0;
246 0 : }
247 151 : bool IsPreviousMarginDirty() const {
248 151 : return mFlags.mPreviousMarginDirty;
249 : }
250 :
251 : // mHasClearance bit
252 0 : void SetHasClearance() {
253 0 : mFlags.mHasClearance = 1;
254 0 : }
255 10 : void ClearHasClearance() {
256 10 : mFlags.mHasClearance = 0;
257 10 : }
258 11 : bool HasClearance() const {
259 11 : return mFlags.mHasClearance;
260 : }
261 :
262 : // mImpactedByFloat bit
263 85 : void SetLineIsImpactedByFloat(bool aValue) {
264 85 : mFlags.mImpactedByFloat = aValue;
265 85 : }
266 0 : bool IsImpactedByFloat() const {
267 0 : return mFlags.mImpactedByFloat;
268 : }
269 :
270 : // mLineWrapped bit
271 75 : void SetLineWrapped(bool aOn) {
272 75 : mFlags.mLineWrapped = aOn;
273 75 : }
274 75 : bool IsLineWrapped() const {
275 75 : return mFlags.mLineWrapped;
276 : }
277 :
278 : // mInvalidateTextRuns bit
279 33 : void SetInvalidateTextRuns(bool aOn) {
280 33 : mFlags.mInvalidateTextRuns = aOn;
281 33 : }
282 41 : bool GetInvalidateTextRuns() const {
283 41 : return mFlags.mInvalidateTextRuns;
284 : }
285 :
286 : // mResizeReflowOptimizationDisabled bit
287 4 : void DisableResizeReflowOptimization() {
288 4 : mFlags.mResizeReflowOptimizationDisabled = true;
289 4 : }
290 75 : void EnableResizeReflowOptimization() {
291 75 : mFlags.mResizeReflowOptimizationDisabled = false;
292 75 : }
293 0 : bool ResizeReflowOptimizationDisabled() const {
294 0 : return mFlags.mResizeReflowOptimizationDisabled;
295 : }
296 :
297 : // mHasBullet bit
298 0 : void SetHasBullet() {
299 0 : mFlags.mHasBullet = true;
300 0 : InvalidateCachedIsEmpty();
301 0 : }
302 75 : void ClearHasBullet() {
303 75 : mFlags.mHasBullet = false;
304 75 : InvalidateCachedIsEmpty();
305 75 : }
306 140 : bool HasBullet() const {
307 140 : return mFlags.mHasBullet;
308 : }
309 :
310 : // mHadFloatPushed bit
311 0 : void SetHadFloatPushed() {
312 0 : mFlags.mHadFloatPushed = true;
313 0 : }
314 85 : void ClearHadFloatPushed() {
315 85 : mFlags.mHadFloatPushed = false;
316 85 : }
317 0 : bool HadFloatPushed() const {
318 0 : return mFlags.mHadFloatPushed;
319 : }
320 :
321 : private:
322 : // Add a hash table for fast lookup when the line has more frames than this.
323 : static const uint32_t kMinChildCountForHashtable = 200;
324 :
325 : /**
326 : * Take ownership of aFromLine's hash table and remove the frames that
327 : * stay on aFromLine from it, i.e. aFromLineNewCount frames starting with
328 : * mFirstChild. This method is used to optimize moving a large number
329 : * of frames from one line to the next.
330 : */
331 : void StealHashTableFrom(nsLineBox* aFromLine, uint32_t aFromLineNewCount);
332 :
333 : /**
334 : * Does the equivalent of this->NoteFrameAdded and aFromLine->NoteFrameRemoved
335 : * for each frame on this line, but in a optimized way.
336 : */
337 : void NoteFramesMovedFrom(nsLineBox* aFromLine);
338 :
339 0 : void SwitchToHashtable()
340 : {
341 0 : MOZ_ASSERT(!mFlags.mHasHashedFrames);
342 0 : uint32_t count = GetChildCount();
343 0 : mFlags.mHasHashedFrames = 1;
344 0 : uint32_t minLength = std::max(kMinChildCountForHashtable,
345 0 : uint32_t(PLDHashTable::kDefaultInitialLength));
346 0 : mFrames = new nsTHashtable< nsPtrHashKey<nsIFrame> >(std::max(count, minLength));
347 0 : for (nsIFrame* f = mFirstChild; count-- > 0; f = f->GetNextSibling()) {
348 0 : mFrames->PutEntry(f);
349 : }
350 0 : }
351 0 : void SwitchToCounter() {
352 0 : MOZ_ASSERT(mFlags.mHasHashedFrames);
353 0 : uint32_t count = GetChildCount();
354 0 : delete mFrames;
355 0 : mFlags.mHasHashedFrames = 0;
356 0 : mChildCount = count;
357 0 : }
358 :
359 : public:
360 721 : int32_t GetChildCount() const {
361 721 : return MOZ_UNLIKELY(mFlags.mHasHashedFrames) ? mFrames->Count() : mChildCount;
362 : }
363 :
364 : /**
365 : * Register that aFrame is now on this line.
366 : */
367 0 : void NoteFrameAdded(nsIFrame* aFrame) {
368 0 : if (MOZ_UNLIKELY(mFlags.mHasHashedFrames)) {
369 0 : mFrames->PutEntry(aFrame);
370 : } else {
371 0 : if (++mChildCount >= kMinChildCountForHashtable) {
372 0 : SwitchToHashtable();
373 : }
374 : }
375 0 : }
376 :
377 : /**
378 : * Register that aFrame is not on this line anymore.
379 : */
380 12 : void NoteFrameRemoved(nsIFrame* aFrame) {
381 12 : MOZ_ASSERT(GetChildCount() > 0);
382 12 : if (MOZ_UNLIKELY(mFlags.mHasHashedFrames)) {
383 0 : mFrames->RemoveEntry(aFrame);
384 0 : if (mFrames->Count() < kMinChildCountForHashtable) {
385 0 : SwitchToCounter();
386 : }
387 : } else {
388 12 : --mChildCount;
389 : }
390 12 : }
391 :
392 : // mBreakType value
393 : // Break information is applied *before* the line if the line is a block,
394 : // or *after* the line if the line is an inline. Confusing, I know, but
395 : // using different names should help.
396 : using StyleClear = mozilla::StyleClear;
397 : bool HasBreakBefore() const {
398 : return IsBlock() && StyleClear::None != BreakType();
399 : }
400 10 : void SetBreakTypeBefore(StyleClear aBreakType) {
401 10 : MOZ_ASSERT(IsBlock(), "Only blocks have break-before");
402 10 : MOZ_ASSERT(aBreakType == StyleClear::None ||
403 : aBreakType == StyleClear::Left ||
404 : aBreakType == StyleClear::Right ||
405 : aBreakType == StyleClear::Both,
406 : "Only float break types are allowed before a line");
407 10 : mFlags.mBreakType = aBreakType;
408 10 : }
409 76 : StyleClear GetBreakTypeBefore() const {
410 76 : return IsBlock() ? BreakType() : StyleClear::None;
411 : }
412 :
413 0 : bool HasBreakAfter() const {
414 0 : return !IsBlock() && StyleClear::None != BreakType();
415 : }
416 84 : void SetBreakTypeAfter(StyleClear aBreakType) {
417 84 : MOZ_ASSERT(!IsBlock(), "Only inlines have break-after");
418 84 : mFlags.mBreakType = aBreakType;
419 84 : }
420 367 : bool HasFloatBreakAfter() const {
421 724 : return !IsBlock() &&
422 714 : (StyleClear::Left == BreakType() ||
423 714 : StyleClear::Right == BreakType() ||
424 724 : StyleClear::Both == BreakType());
425 : }
426 0 : StyleClear GetBreakTypeAfter() const {
427 0 : return !IsBlock() ? BreakType() : StyleClear::None;
428 : }
429 :
430 : // mCarriedOutBEndMargin value
431 : nsCollapsingMargin GetCarriedOutBEndMargin() const;
432 : // Returns true if the margin changed
433 : bool SetCarriedOutBEndMargin(nsCollapsingMargin aValue);
434 :
435 : // mFloats
436 485 : bool HasFloats() const {
437 485 : return (IsInline() && mInlineData) && mInlineData->mFloats.NotEmpty();
438 : }
439 : nsFloatCache* GetFirstFloat();
440 : void FreeFloats(nsFloatCacheFreeList& aFreeList);
441 : void AppendFloats(nsFloatCacheFreeList& aFreeList);
442 : bool RemoveFloat(nsIFrame* aFrame);
443 :
444 : // Combined area is the area of the line that should influence the
445 : // overflow area of its parent block. The combined area should be
446 : // used for painting-related things, but should never be used for
447 : // layout (except for handling of 'overflow').
448 : void SetOverflowAreas(const nsOverflowAreas& aOverflowAreas);
449 0 : mozilla::LogicalRect GetOverflowArea(nsOverflowType aType,
450 : mozilla::WritingMode aWM,
451 : const nsSize& aContainerSize)
452 : {
453 0 : return mozilla::LogicalRect(aWM, GetOverflowArea(aType), aContainerSize);
454 : }
455 197 : nsRect GetOverflowArea(nsOverflowType aType) {
456 197 : return mData ? mData->mOverflowAreas.Overflow(aType) : GetPhysicalBounds();
457 : }
458 151 : nsOverflowAreas GetOverflowAreas() {
459 151 : if (mData) {
460 62 : return mData->mOverflowAreas;
461 : }
462 178 : nsRect bounds = GetPhysicalBounds();
463 89 : return nsOverflowAreas(bounds, bounds);
464 : }
465 197 : nsRect GetVisualOverflowArea()
466 197 : { return GetOverflowArea(eVisualOverflow); }
467 0 : nsRect GetScrollableOverflowArea()
468 0 : { return GetOverflowArea(eScrollableOverflow); }
469 :
470 0 : void SlideBy(nscoord aDBCoord, const nsSize& aContainerSize) {
471 0 : NS_ASSERTION(aContainerSize == mContainerSize ||
472 : mContainerSize == nsSize(-1, -1),
473 : "container size doesn't match");
474 0 : mContainerSize = aContainerSize;
475 0 : mBounds.BStart(mWritingMode) += aDBCoord;
476 0 : if (mData) {
477 : // Use a null containerSize to convert vector from logical to physical.
478 0 : const nsSize nullContainerSize;
479 : nsPoint physicalDelta =
480 0 : mozilla::LogicalPoint(mWritingMode, 0, aDBCoord).
481 0 : GetPhysicalPoint(mWritingMode, nullContainerSize);
482 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
483 0 : mData->mOverflowAreas.Overflow(otype) += physicalDelta;
484 : }
485 : }
486 0 : }
487 :
488 : // Container-size for the line is changing (and therefore if writing mode
489 : // was vertical-rl, the line will move physically; this is like SlideBy,
490 : // but it is the container size instead of the line's own logical coord
491 : // that is changing.
492 0 : nsSize UpdateContainerSize(const nsSize aNewContainerSize)
493 : {
494 0 : NS_ASSERTION(mContainerSize != nsSize(-1, -1), "container size not set");
495 0 : nsSize delta = mContainerSize - aNewContainerSize;
496 0 : mContainerSize = aNewContainerSize;
497 : // this has a physical-coordinate effect only in vertical-rl mode
498 0 : if (mWritingMode.IsVerticalRL() && mData) {
499 0 : nsPoint physicalDelta(-delta.width, 0);
500 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
501 0 : mData->mOverflowAreas.Overflow(otype) += physicalDelta;
502 : }
503 : }
504 0 : return delta;
505 : }
506 :
507 0 : void IndentBy(nscoord aDICoord, const nsSize& aContainerSize) {
508 0 : NS_ASSERTION(aContainerSize == mContainerSize ||
509 : mContainerSize == nsSize(-1, -1),
510 : "container size doesn't match");
511 0 : mContainerSize = aContainerSize;
512 0 : mBounds.IStart(mWritingMode) += aDICoord;
513 0 : }
514 :
515 0 : void ExpandBy(nscoord aDISize, const nsSize& aContainerSize) {
516 0 : NS_ASSERTION(aContainerSize == mContainerSize ||
517 : mContainerSize == nsSize(-1, -1),
518 : "container size doesn't match");
519 0 : mContainerSize = aContainerSize;
520 0 : mBounds.ISize(mWritingMode) += aDISize;
521 0 : }
522 :
523 : /**
524 : * The logical ascent (distance from block-start to baseline) of the
525 : * linebox is the logical ascent of the anonymous inline box (for
526 : * which we don't actually create a frame) that wraps all the
527 : * consecutive inline children of a block.
528 : *
529 : * This is currently unused for block lines.
530 : */
531 5 : nscoord GetLogicalAscent() const { return mAscent; }
532 75 : void SetLogicalAscent(nscoord aAscent) { mAscent = aAscent; }
533 :
534 454 : nscoord BStart() const {
535 454 : return mBounds.BStart(mWritingMode);
536 : }
537 192 : nscoord BSize() const {
538 192 : return mBounds.BSize(mWritingMode);
539 : }
540 451 : nscoord BEnd() const {
541 451 : return mBounds.BEnd(mWritingMode);
542 : }
543 85 : nscoord IStart() const {
544 85 : return mBounds.IStart(mWritingMode);
545 : }
546 129 : nscoord ISize() const {
547 129 : return mBounds.ISize(mWritingMode);
548 : }
549 0 : nscoord IEnd() const {
550 0 : return mBounds.IEnd(mWritingMode);
551 : }
552 0 : void SetBoundsEmpty() {
553 0 : mBounds.IStart(mWritingMode) = 0;
554 0 : mBounds.ISize(mWritingMode) = 0;
555 0 : mBounds.BStart(mWritingMode) = 0;
556 0 : mBounds.BSize(mWritingMode) = 0;
557 0 : }
558 :
559 : static void DeleteLineList(nsPresContext* aPresContext, nsLineList& aLines,
560 : nsIFrame* aDestructRoot, nsFrameList* aFrames);
561 :
562 : // search from end to beginning of [aBegin, aEnd)
563 : // Returns true if it found the line and false if not.
564 : // Moves aEnd as it searches so that aEnd points to the resulting line.
565 : // aLastFrameBeforeEnd is the last frame before aEnd (so if aEnd is
566 : // the end of the line list, it's just the last frame in the frame
567 : // list).
568 : static bool RFindLineContaining(nsIFrame* aFrame,
569 : const nsLineList_iterator& aBegin,
570 : nsLineList_iterator& aEnd,
571 : nsIFrame* aLastFrameBeforeEnd,
572 : int32_t* aFrameIndexInLine);
573 :
574 : #ifdef DEBUG_FRAME_DUMP
575 : const char* BreakTypeToString(StyleClear aBreakType) const;
576 : char* StateToString(char* aBuf, int32_t aBufSize) const;
577 :
578 : void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const;
579 : void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const;
580 : nsIFrame* LastChild() const;
581 : #endif
582 :
583 : private:
584 : int32_t IndexOf(nsIFrame* aFrame) const;
585 : public:
586 :
587 12 : bool Contains(nsIFrame* aFrame) const {
588 24 : return MOZ_UNLIKELY(mFlags.mHasHashedFrames) ? mFrames->Contains(aFrame)
589 24 : : IndexOf(aFrame) >= 0;
590 : }
591 :
592 : // whether the line box is "logically" empty (just like nsIFrame::IsEmpty)
593 : bool IsEmpty() const;
594 :
595 : // Call this only while in Reflow() for the block the line belongs
596 : // to, only between reflowing the line (or sliding it, if we skip
597 : // reflowing it) and the end of reflowing the block.
598 : bool CachedIsEmpty();
599 :
600 160 : void InvalidateCachedIsEmpty() {
601 160 : mFlags.mEmptyCacheValid = false;
602 160 : }
603 :
604 : // For debugging purposes
605 : bool IsValidCachedIsEmpty() {
606 : return mFlags.mEmptyCacheValid;
607 : }
608 :
609 : #ifdef DEBUG
610 : static int32_t GetCtorCount();
611 : #endif
612 :
613 : nsIFrame* mFirstChild;
614 :
615 : mozilla::WritingMode mWritingMode;
616 :
617 : // Physical size. Use only for physical <-> logical coordinate conversion.
618 : nsSize mContainerSize;
619 :
620 : private:
621 : mozilla::LogicalRect mBounds;
622 :
623 : public:
624 0 : const mozilla::LogicalRect& GetBounds() { return mBounds; }
625 323 : nsRect GetPhysicalBounds() const
626 : {
627 323 : if (mBounds.IsAllZero()) {
628 47 : return nsRect(0, 0, 0, 0);
629 : }
630 :
631 276 : NS_ASSERTION(mContainerSize != nsSize(-1, -1),
632 : "mContainerSize not initialized");
633 276 : return mBounds.GetPhysicalRect(mWritingMode, mContainerSize);
634 : }
635 85 : void SetBounds(mozilla::WritingMode aWritingMode,
636 : nscoord aIStart, nscoord aBStart,
637 : nscoord aISize, nscoord aBSize,
638 : const nsSize& aContainerSize)
639 : {
640 85 : mWritingMode = aWritingMode;
641 85 : mContainerSize = aContainerSize;
642 85 : mBounds = mozilla::LogicalRect(aWritingMode, aIStart, aBStart,
643 : aISize, aBSize);
644 85 : }
645 : void SetBounds(mozilla::WritingMode aWritingMode,
646 : nsRect aRect, const nsSize& aContainerSize)
647 : {
648 : mWritingMode = aWritingMode;
649 : mContainerSize = aContainerSize;
650 : mBounds = mozilla::LogicalRect(aWritingMode, aRect, aContainerSize);
651 : }
652 :
653 : // mFlags.mHasHashedFrames says which one to use
654 : union {
655 : nsTHashtable< nsPtrHashKey<nsIFrame> >* mFrames;
656 : uint32_t mChildCount;
657 : };
658 :
659 : struct FlagBits {
660 : bool mDirty : 1;
661 : bool mPreviousMarginDirty : 1;
662 : bool mHasClearance : 1;
663 : bool mBlock : 1;
664 : bool mImpactedByFloat : 1;
665 : bool mLineWrapped: 1;
666 : bool mInvalidateTextRuns : 1;
667 : // default 0 = means that the opt potentially applies to this line.
668 : // 1 = never skip reflowing this line for a resize reflow
669 : bool mResizeReflowOptimizationDisabled: 1;
670 : bool mEmptyCacheValid: 1;
671 : bool mEmptyCacheState: 1;
672 : // mHasBullet indicates that this is an inline line whose block's
673 : // bullet is adjacent to this line and non-empty.
674 : bool mHasBullet : 1;
675 : // Indicates that this line *may* have a placeholder for a float
676 : // that was pushed to a later column or page.
677 : bool mHadFloatPushed : 1;
678 : bool mHasHashedFrames: 1;
679 : StyleClear mBreakType;
680 : };
681 :
682 5 : struct ExtraData {
683 11 : explicit ExtraData(const nsRect& aBounds) : mOverflowAreas(aBounds, aBounds) {
684 11 : }
685 : nsOverflowAreas mOverflowAreas;
686 : };
687 :
688 0 : struct ExtraBlockData : public ExtraData {
689 2 : explicit ExtraBlockData(const nsRect& aBounds)
690 2 : : ExtraData(aBounds),
691 2 : mCarriedOutBEndMargin()
692 : {
693 2 : }
694 : nsCollapsingMargin mCarriedOutBEndMargin;
695 : };
696 :
697 5 : struct ExtraInlineData : public ExtraData {
698 9 : explicit ExtraInlineData(const nsRect& aBounds)
699 9 : : ExtraData(aBounds)
700 : , mFloatEdgeIStart(nscoord_MIN)
701 9 : , mFloatEdgeIEnd(nscoord_MIN)
702 9 : {}
703 : nscoord mFloatEdgeIStart;
704 : nscoord mFloatEdgeIEnd;
705 : nsFloatCacheList mFloats;
706 : };
707 :
708 0 : bool GetFloatEdges(nscoord* aStart, nscoord* aEnd) const {
709 0 : MOZ_ASSERT(IsInline(), "block line can't have float edges");
710 0 : if (mInlineData && mInlineData->mFloatEdgeIStart != nscoord_MIN) {
711 0 : *aStart = mInlineData->mFloatEdgeIStart;
712 0 : *aEnd = mInlineData->mFloatEdgeIEnd;
713 0 : return true;
714 : }
715 0 : return false;
716 : }
717 : void SetFloatEdges(nscoord aStart, nscoord aEnd);
718 : void ClearFloatEdges();
719 :
720 : protected:
721 : nscoord mAscent; // see |SetAscent| / |GetAscent|
722 : static_assert(sizeof(FlagBits) <= sizeof(uint32_t),
723 : "size of FlagBits should not be larger than size of uint32_t");
724 : union {
725 : uint32_t mAllFlags;
726 : FlagBits mFlags;
727 : };
728 :
729 1081 : StyleClear BreakType() const {
730 1081 : return mFlags.mBreakType;
731 : };
732 :
733 : union {
734 : ExtraData* mData;
735 : ExtraBlockData* mBlockData;
736 : ExtraInlineData* mInlineData;
737 : };
738 :
739 : void Cleanup();
740 : void MaybeFreeData();
741 : };
742 :
743 : /**
744 : * A linked list type where the items in the list must inherit from
745 : * a link type to fuse allocations.
746 : *
747 : * API heavily based on the |list| class in the C++ standard.
748 : */
749 :
750 : class nsLineList_iterator {
751 : public:
752 : friend class nsLineList;
753 : friend class nsLineList_reverse_iterator;
754 : friend class nsLineList_const_iterator;
755 : friend class nsLineList_const_reverse_iterator;
756 :
757 : typedef nsLineList_iterator iterator_self_type;
758 : typedef nsLineList_reverse_iterator iterator_reverse_type;
759 :
760 : typedef nsLineBox& reference;
761 : typedef const nsLineBox& const_reference;
762 :
763 : typedef nsLineBox* pointer;
764 : typedef const nsLineBox* const_pointer;
765 :
766 : typedef uint32_t size_type;
767 : typedef int32_t difference_type;
768 :
769 : typedef nsLineLink link_type;
770 :
771 : #ifdef DEBUG
772 2823 : nsLineList_iterator() { memset(&mCurrent, 0xcd, sizeof(mCurrent)); }
773 : #else
774 : // Auto generated default constructor OK.
775 : #endif
776 : // Auto generated copy-constructor OK.
777 :
778 : inline iterator_self_type&
779 : operator=(const iterator_self_type& aOther);
780 : inline iterator_self_type&
781 : operator=(const iterator_reverse_type& aOther);
782 :
783 967 : iterator_self_type& operator++()
784 : {
785 967 : mCurrent = mCurrent->_mNext;
786 967 : return *this;
787 : }
788 :
789 0 : iterator_self_type operator++(int)
790 : {
791 0 : iterator_self_type rv(*this);
792 0 : mCurrent = mCurrent->_mNext;
793 0 : return rv;
794 : }
795 :
796 82 : iterator_self_type& operator--()
797 : {
798 82 : mCurrent = mCurrent->_mPrev;
799 82 : return *this;
800 : }
801 :
802 0 : iterator_self_type operator--(int)
803 : {
804 0 : iterator_self_type rv(*this);
805 0 : mCurrent = mCurrent->_mPrev;
806 0 : return rv;
807 : }
808 :
809 : reference operator*()
810 : {
811 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
812 : return *static_cast<pointer>(mCurrent);
813 : }
814 :
815 7259 : pointer operator->()
816 : {
817 7259 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
818 7259 : return static_cast<pointer>(mCurrent);
819 : }
820 :
821 414 : pointer get()
822 : {
823 414 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
824 414 : return static_cast<pointer>(mCurrent);
825 : }
826 :
827 718 : operator pointer()
828 : {
829 718 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
830 718 : return static_cast<pointer>(mCurrent);
831 : }
832 :
833 : const_reference operator*() const
834 : {
835 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
836 : return *static_cast<const_pointer>(mCurrent);
837 : }
838 :
839 41 : const_pointer operator->() const
840 : {
841 41 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
842 41 : return static_cast<const_pointer>(mCurrent);
843 : }
844 :
845 : #ifndef __MWERKS__
846 : operator const_pointer() const
847 : {
848 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
849 : return static_cast<const_pointer>(mCurrent);
850 : }
851 : #endif /* !__MWERKS__ */
852 :
853 163 : iterator_self_type next()
854 : {
855 163 : iterator_self_type copy(*this);
856 163 : return ++copy;
857 : }
858 :
859 : const iterator_self_type next() const
860 : {
861 : iterator_self_type copy(*this);
862 : return ++copy;
863 : }
864 :
865 0 : iterator_self_type prev()
866 : {
867 0 : iterator_self_type copy(*this);
868 0 : return --copy;
869 : }
870 :
871 : const iterator_self_type prev() const
872 : {
873 : iterator_self_type copy(*this);
874 : return --copy;
875 : }
876 :
877 : // Passing by value rather than by reference and reference to const
878 : // to keep AIX happy.
879 : bool operator==(const iterator_self_type aOther) const
880 : {
881 : MOZ_ASSERT(mListLink == aOther.mListLink, "comparing iterators over different lists");
882 : return mCurrent == aOther.mCurrent;
883 : }
884 0 : bool operator!=(const iterator_self_type aOther) const
885 : {
886 0 : MOZ_ASSERT(mListLink == aOther.mListLink, "comparing iterators over different lists");
887 0 : return mCurrent != aOther.mCurrent;
888 : }
889 282 : bool operator==(const iterator_self_type aOther)
890 : {
891 282 : MOZ_ASSERT(mListLink == aOther.mListLink, "comparing iterators over different lists");
892 282 : return mCurrent == aOther.mCurrent;
893 : }
894 1878 : bool operator!=(const iterator_self_type aOther)
895 : {
896 1878 : MOZ_ASSERT(mListLink == aOther.mListLink, "comparing iterators over different lists");
897 1878 : return mCurrent != aOther.mCurrent;
898 : }
899 :
900 : private:
901 : link_type *mCurrent;
902 : #ifdef DEBUG
903 : link_type *mListLink; // the list's link, i.e., the end
904 : #endif
905 : };
906 :
907 : class nsLineList_reverse_iterator {
908 :
909 : public:
910 :
911 : friend class nsLineList;
912 : friend class nsLineList_iterator;
913 : friend class nsLineList_const_iterator;
914 : friend class nsLineList_const_reverse_iterator;
915 :
916 : typedef nsLineList_reverse_iterator iterator_self_type;
917 : typedef nsLineList_iterator iterator_reverse_type;
918 :
919 : typedef nsLineBox& reference;
920 : typedef const nsLineBox& const_reference;
921 :
922 : typedef nsLineBox* pointer;
923 : typedef const nsLineBox* const_pointer;
924 :
925 : typedef uint32_t size_type;
926 : typedef int32_t difference_type;
927 :
928 : typedef nsLineLink link_type;
929 :
930 : #ifdef DEBUG
931 0 : nsLineList_reverse_iterator() { memset(&mCurrent, 0xcd, sizeof(mCurrent)); }
932 : #else
933 : // Auto generated default constructor OK.
934 : #endif
935 : // Auto generated copy-constructor OK.
936 :
937 : inline iterator_self_type&
938 : operator=(const iterator_reverse_type& aOther);
939 : inline iterator_self_type&
940 : operator=(const iterator_self_type& aOther);
941 :
942 0 : iterator_self_type& operator++()
943 : {
944 0 : mCurrent = mCurrent->_mPrev;
945 0 : return *this;
946 : }
947 :
948 : iterator_self_type operator++(int)
949 : {
950 : iterator_self_type rv(*this);
951 : mCurrent = mCurrent->_mPrev;
952 : return rv;
953 : }
954 :
955 : iterator_self_type& operator--()
956 : {
957 : mCurrent = mCurrent->_mNext;
958 : return *this;
959 : }
960 :
961 : iterator_self_type operator--(int)
962 : {
963 : iterator_self_type rv(*this);
964 : mCurrent = mCurrent->_mNext;
965 : return rv;
966 : }
967 :
968 : reference operator*()
969 : {
970 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
971 : return *static_cast<pointer>(mCurrent);
972 : }
973 :
974 0 : pointer operator->()
975 : {
976 0 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
977 0 : return static_cast<pointer>(mCurrent);
978 : }
979 :
980 : pointer get()
981 : {
982 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
983 : return static_cast<pointer>(mCurrent);
984 : }
985 :
986 : operator pointer()
987 : {
988 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
989 : return static_cast<pointer>(mCurrent);
990 : }
991 :
992 : const_reference operator*() const
993 : {
994 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
995 : return *static_cast<const_pointer>(mCurrent);
996 : }
997 :
998 : const_pointer operator->() const
999 : {
1000 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
1001 : return static_cast<const_pointer>(mCurrent);
1002 : }
1003 :
1004 : #ifndef __MWERKS__
1005 : operator const_pointer() const
1006 : {
1007 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
1008 : return static_cast<const_pointer>(mCurrent);
1009 : }
1010 : #endif /* !__MWERKS__ */
1011 :
1012 : // Passing by value rather than by reference and reference to const
1013 : // to keep AIX happy.
1014 : bool operator==(const iterator_self_type aOther) const
1015 : {
1016 : NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1017 : return mCurrent == aOther.mCurrent;
1018 : }
1019 : bool operator!=(const iterator_self_type aOther) const
1020 : {
1021 : NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1022 : return mCurrent != aOther.mCurrent;
1023 : }
1024 : bool operator==(const iterator_self_type aOther)
1025 : {
1026 : NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1027 : return mCurrent == aOther.mCurrent;
1028 : }
1029 0 : bool operator!=(const iterator_self_type aOther)
1030 : {
1031 0 : NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1032 0 : return mCurrent != aOther.mCurrent;
1033 : }
1034 :
1035 : private:
1036 : link_type *mCurrent;
1037 : #ifdef DEBUG
1038 : link_type *mListLink; // the list's link, i.e., the end
1039 : #endif
1040 : };
1041 :
1042 : class nsLineList_const_iterator {
1043 : public:
1044 :
1045 : friend class nsLineList;
1046 : friend class nsLineList_iterator;
1047 : friend class nsLineList_reverse_iterator;
1048 : friend class nsLineList_const_reverse_iterator;
1049 :
1050 : typedef nsLineList_const_iterator iterator_self_type;
1051 : typedef nsLineList_const_reverse_iterator iterator_reverse_type;
1052 : typedef nsLineList_iterator iterator_nonconst_type;
1053 : typedef nsLineList_reverse_iterator iterator_nonconst_reverse_type;
1054 :
1055 : typedef nsLineBox& reference;
1056 : typedef const nsLineBox& const_reference;
1057 :
1058 : typedef nsLineBox* pointer;
1059 : typedef const nsLineBox* const_pointer;
1060 :
1061 : typedef uint32_t size_type;
1062 : typedef int32_t difference_type;
1063 :
1064 : typedef nsLineLink link_type;
1065 :
1066 : #ifdef DEBUG
1067 70 : nsLineList_const_iterator() { memset(&mCurrent, 0xcd, sizeof(mCurrent)); }
1068 : #else
1069 : // Auto generated default constructor OK.
1070 : #endif
1071 : // Auto generated copy-constructor OK.
1072 :
1073 : inline iterator_self_type&
1074 : operator=(const iterator_nonconst_type& aOther);
1075 : inline iterator_self_type&
1076 : operator=(const iterator_nonconst_reverse_type& aOther);
1077 : inline iterator_self_type&
1078 : operator=(const iterator_self_type& aOther);
1079 : inline iterator_self_type&
1080 : operator=(const iterator_reverse_type& aOther);
1081 :
1082 30 : iterator_self_type& operator++()
1083 : {
1084 30 : mCurrent = mCurrent->_mNext;
1085 30 : return *this;
1086 : }
1087 :
1088 : iterator_self_type operator++(int)
1089 : {
1090 : iterator_self_type rv(*this);
1091 : mCurrent = mCurrent->_mNext;
1092 : return rv;
1093 : }
1094 :
1095 : iterator_self_type& operator--()
1096 : {
1097 : mCurrent = mCurrent->_mPrev;
1098 : return *this;
1099 : }
1100 :
1101 : iterator_self_type operator--(int)
1102 : {
1103 : iterator_self_type rv(*this);
1104 : mCurrent = mCurrent->_mPrev;
1105 : return rv;
1106 : }
1107 :
1108 : const_reference operator*() const
1109 : {
1110 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
1111 : return *static_cast<const_pointer>(mCurrent);
1112 : }
1113 :
1114 115 : const_pointer operator->() const
1115 : {
1116 115 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
1117 115 : return static_cast<const_pointer>(mCurrent);
1118 : }
1119 :
1120 : const_pointer get() const
1121 : {
1122 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
1123 : return static_cast<const_pointer>(mCurrent);
1124 : }
1125 :
1126 : #ifndef __MWERKS__
1127 0 : operator const_pointer() const
1128 : {
1129 0 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
1130 0 : return static_cast<const_pointer>(mCurrent);
1131 : }
1132 : #endif /* !__MWERKS__ */
1133 :
1134 : const iterator_self_type next() const
1135 : {
1136 : iterator_self_type copy(*this);
1137 : return ++copy;
1138 : }
1139 :
1140 : const iterator_self_type prev() const
1141 : {
1142 : iterator_self_type copy(*this);
1143 : return --copy;
1144 : }
1145 :
1146 : // Passing by value rather than by reference and reference to const
1147 : // to keep AIX happy.
1148 : bool operator==(const iterator_self_type aOther) const
1149 : {
1150 : NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1151 : return mCurrent == aOther.mCurrent;
1152 : }
1153 : bool operator!=(const iterator_self_type aOther) const
1154 : {
1155 : NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1156 : return mCurrent != aOther.mCurrent;
1157 : }
1158 : bool operator==(const iterator_self_type aOther)
1159 : {
1160 : NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1161 : return mCurrent == aOther.mCurrent;
1162 : }
1163 65 : bool operator!=(const iterator_self_type aOther)
1164 : {
1165 65 : NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1166 65 : return mCurrent != aOther.mCurrent;
1167 : }
1168 :
1169 : private:
1170 : const link_type *mCurrent;
1171 : #ifdef DEBUG
1172 : const link_type *mListLink; // the list's link, i.e., the end
1173 : #endif
1174 : };
1175 :
1176 : class nsLineList_const_reverse_iterator {
1177 : public:
1178 :
1179 : friend class nsLineList;
1180 : friend class nsLineList_iterator;
1181 : friend class nsLineList_reverse_iterator;
1182 : friend class nsLineList_const_iterator;
1183 :
1184 : typedef nsLineList_const_reverse_iterator iterator_self_type;
1185 : typedef nsLineList_const_iterator iterator_reverse_type;
1186 : typedef nsLineList_iterator iterator_nonconst_reverse_type;
1187 : typedef nsLineList_reverse_iterator iterator_nonconst_type;
1188 :
1189 : typedef nsLineBox& reference;
1190 : typedef const nsLineBox& const_reference;
1191 :
1192 : typedef nsLineBox* pointer;
1193 : typedef const nsLineBox* const_pointer;
1194 :
1195 : typedef uint32_t size_type;
1196 : typedef int32_t difference_type;
1197 :
1198 : typedef nsLineLink link_type;
1199 :
1200 : #ifdef DEBUG
1201 60 : nsLineList_const_reverse_iterator() { memset(&mCurrent, 0xcd, sizeof(mCurrent)); }
1202 : #else
1203 : // Auto generated default constructor OK.
1204 : #endif
1205 : // Auto generated copy-constructor OK.
1206 :
1207 : inline iterator_self_type&
1208 : operator=(const iterator_nonconst_type& aOther);
1209 : inline iterator_self_type&
1210 : operator=(const iterator_nonconst_reverse_type& aOther);
1211 : inline iterator_self_type&
1212 : operator=(const iterator_self_type& aOther);
1213 : inline iterator_self_type&
1214 : operator=(const iterator_reverse_type& aOther);
1215 :
1216 30 : iterator_self_type& operator++()
1217 : {
1218 30 : mCurrent = mCurrent->_mPrev;
1219 30 : return *this;
1220 : }
1221 :
1222 : iterator_self_type operator++(int)
1223 : {
1224 : iterator_self_type rv(*this);
1225 : mCurrent = mCurrent->_mPrev;
1226 : return rv;
1227 : }
1228 :
1229 : iterator_self_type& operator--()
1230 : {
1231 : mCurrent = mCurrent->_mNext;
1232 : return *this;
1233 : }
1234 :
1235 : iterator_self_type operator--(int)
1236 : {
1237 : iterator_self_type rv(*this);
1238 : mCurrent = mCurrent->_mNext;
1239 : return rv;
1240 : }
1241 :
1242 : const_reference operator*() const
1243 : {
1244 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
1245 : return *static_cast<const_pointer>(mCurrent);
1246 : }
1247 :
1248 90 : const_pointer operator->() const
1249 : {
1250 90 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
1251 90 : return static_cast<const_pointer>(mCurrent);
1252 : }
1253 :
1254 : const_pointer get() const
1255 : {
1256 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
1257 : return static_cast<const_pointer>(mCurrent);
1258 : }
1259 :
1260 : #ifndef __MWERKS__
1261 : operator const_pointer() const
1262 : {
1263 : MOZ_ASSERT(mCurrent != mListLink, "running past end");
1264 : return static_cast<const_pointer>(mCurrent);
1265 : }
1266 : #endif /* !__MWERKS__ */
1267 :
1268 : // Passing by value rather than by reference and reference to const
1269 : // to keep AIX happy.
1270 : bool operator==(const iterator_self_type aOther) const
1271 : {
1272 : NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1273 : return mCurrent == aOther.mCurrent;
1274 : }
1275 : bool operator!=(const iterator_self_type aOther) const
1276 : {
1277 : NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1278 : return mCurrent != aOther.mCurrent;
1279 : }
1280 : bool operator==(const iterator_self_type aOther)
1281 : {
1282 : NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1283 : return mCurrent == aOther.mCurrent;
1284 : }
1285 60 : bool operator!=(const iterator_self_type aOther)
1286 : {
1287 60 : NS_ASSERTION(mListLink == aOther.mListLink, "comparing iterators over different lists");
1288 60 : return mCurrent != aOther.mCurrent;
1289 : }
1290 :
1291 : //private:
1292 : const link_type *mCurrent;
1293 : #ifdef DEBUG
1294 : const link_type *mListLink; // the list's link, i.e., the end
1295 : #endif
1296 : };
1297 :
1298 : class nsLineList {
1299 :
1300 : public:
1301 :
1302 : friend class nsLineList_iterator;
1303 : friend class nsLineList_reverse_iterator;
1304 : friend class nsLineList_const_iterator;
1305 : friend class nsLineList_const_reverse_iterator;
1306 :
1307 : typedef uint32_t size_type;
1308 : typedef int32_t difference_type;
1309 :
1310 : typedef nsLineLink link_type;
1311 :
1312 : private:
1313 : link_type mLink;
1314 :
1315 : public:
1316 : typedef nsLineList self_type;
1317 :
1318 : typedef nsLineBox& reference;
1319 : typedef const nsLineBox& const_reference;
1320 :
1321 : typedef nsLineBox* pointer;
1322 : typedef const nsLineBox* const_pointer;
1323 :
1324 : typedef nsLineList_iterator iterator;
1325 : typedef nsLineList_reverse_iterator reverse_iterator;
1326 : typedef nsLineList_const_iterator const_iterator;
1327 : typedef nsLineList_const_reverse_iterator const_reverse_iterator;
1328 :
1329 34 : nsLineList()
1330 34 : {
1331 34 : MOZ_COUNT_CTOR(nsLineList);
1332 34 : clear();
1333 34 : }
1334 :
1335 10 : ~nsLineList()
1336 10 : {
1337 10 : MOZ_COUNT_DTOR(nsLineList);
1338 10 : }
1339 :
1340 35 : const_iterator begin() const
1341 : {
1342 35 : const_iterator rv;
1343 35 : rv.mCurrent = mLink._mNext;
1344 : #ifdef DEBUG
1345 35 : rv.mListLink = &mLink;
1346 : #endif
1347 35 : return rv;
1348 : }
1349 :
1350 1064 : iterator begin()
1351 : {
1352 1064 : iterator rv;
1353 1064 : rv.mCurrent = mLink._mNext;
1354 : #ifdef DEBUG
1355 1064 : rv.mListLink = &mLink;
1356 : #endif
1357 1064 : return rv;
1358 : }
1359 :
1360 0 : iterator begin(nsLineBox* aLine)
1361 : {
1362 0 : iterator rv;
1363 0 : rv.mCurrent = aLine;
1364 : #ifdef DEBUG
1365 0 : rv.mListLink = &mLink;
1366 : #endif
1367 0 : return rv;
1368 : }
1369 :
1370 35 : const_iterator end() const
1371 : {
1372 35 : const_iterator rv;
1373 35 : rv.mCurrent = &mLink;
1374 : #ifdef DEBUG
1375 35 : rv.mListLink = &mLink;
1376 : #endif
1377 35 : return rv;
1378 : }
1379 :
1380 1295 : iterator end()
1381 : {
1382 1295 : iterator rv;
1383 1295 : rv.mCurrent = &mLink;
1384 : #ifdef DEBUG
1385 1295 : rv.mListLink = &mLink;
1386 : #endif
1387 1295 : return rv;
1388 : }
1389 :
1390 30 : const_reverse_iterator rbegin() const
1391 : {
1392 30 : const_reverse_iterator rv;
1393 30 : rv.mCurrent = mLink._mPrev;
1394 : #ifdef DEBUG
1395 30 : rv.mListLink = &mLink;
1396 : #endif
1397 30 : return rv;
1398 : }
1399 :
1400 : reverse_iterator rbegin()
1401 : {
1402 : reverse_iterator rv;
1403 : rv.mCurrent = mLink._mPrev;
1404 : #ifdef DEBUG
1405 : rv.mListLink = &mLink;
1406 : #endif
1407 : return rv;
1408 : }
1409 :
1410 0 : reverse_iterator rbegin(nsLineBox* aLine)
1411 : {
1412 0 : reverse_iterator rv;
1413 0 : rv.mCurrent = aLine;
1414 : #ifdef DEBUG
1415 0 : rv.mListLink = &mLink;
1416 : #endif
1417 0 : return rv;
1418 : }
1419 :
1420 30 : const_reverse_iterator rend() const
1421 : {
1422 30 : const_reverse_iterator rv;
1423 30 : rv.mCurrent = &mLink;
1424 : #ifdef DEBUG
1425 30 : rv.mListLink = &mLink;
1426 : #endif
1427 30 : return rv;
1428 : }
1429 :
1430 0 : reverse_iterator rend()
1431 : {
1432 0 : reverse_iterator rv;
1433 0 : rv.mCurrent = &mLink;
1434 : #ifdef DEBUG
1435 0 : rv.mListLink = &mLink;
1436 : #endif
1437 0 : return rv;
1438 : }
1439 :
1440 230 : bool empty() const
1441 : {
1442 230 : return mLink._mNext == &mLink;
1443 : }
1444 :
1445 : // NOTE: O(N).
1446 12 : size_type size() const
1447 : {
1448 12 : size_type count = 0;
1449 24 : for (const link_type *cur = mLink._mNext;
1450 24 : cur != &mLink;
1451 12 : cur = cur->_mNext)
1452 : {
1453 12 : ++count;
1454 : }
1455 12 : return count;
1456 : }
1457 :
1458 81 : pointer front()
1459 : {
1460 81 : NS_ASSERTION(!empty(), "no element to return");
1461 81 : return static_cast<pointer>(mLink._mNext);
1462 : }
1463 :
1464 6 : const_pointer front() const
1465 : {
1466 6 : NS_ASSERTION(!empty(), "no element to return");
1467 6 : return static_cast<const_pointer>(mLink._mNext);
1468 : }
1469 :
1470 88 : pointer back()
1471 : {
1472 88 : NS_ASSERTION(!empty(), "no element to return");
1473 88 : return static_cast<pointer>(mLink._mPrev);
1474 : }
1475 :
1476 : const_pointer back() const
1477 : {
1478 : NS_ASSERTION(!empty(), "no element to return");
1479 : return static_cast<const_pointer>(mLink._mPrev);
1480 : }
1481 :
1482 33 : void push_front(pointer aNew)
1483 : {
1484 33 : aNew->_mNext = mLink._mNext;
1485 33 : mLink._mNext->_mPrev = aNew;
1486 33 : aNew->_mPrev = &mLink;
1487 33 : mLink._mNext = aNew;
1488 33 : }
1489 :
1490 6 : void pop_front()
1491 : // NOTE: leaves dangling next/prev pointers
1492 : {
1493 6 : NS_ASSERTION(!empty(), "no element to pop");
1494 6 : link_type *newFirst = mLink._mNext->_mNext;
1495 6 : newFirst->_mPrev = &mLink;
1496 : // mLink._mNext->_mNext = nullptr;
1497 : // mLink._mNext->_mPrev = nullptr;
1498 6 : mLink._mNext = newFirst;
1499 6 : }
1500 :
1501 : void push_back(pointer aNew)
1502 : {
1503 : aNew->_mPrev = mLink._mPrev;
1504 : mLink._mPrev->_mNext = aNew;
1505 : aNew->_mNext = &mLink;
1506 : mLink._mPrev = aNew;
1507 : }
1508 :
1509 : void pop_back()
1510 : // NOTE: leaves dangling next/prev pointers
1511 : {
1512 : NS_ASSERTION(!empty(), "no element to pop");
1513 : link_type *newLast = mLink._mPrev->_mPrev;
1514 : newLast->_mNext = &mLink;
1515 : // mLink._mPrev->_mPrev = nullptr;
1516 : // mLink._mPrev->_mNext = nullptr;
1517 : mLink._mPrev = newLast;
1518 : }
1519 :
1520 : // inserts x before position
1521 0 : iterator before_insert(iterator position, pointer x)
1522 : {
1523 : // use |mCurrent| to prevent DEBUG_PASS_END assertions
1524 0 : x->_mPrev = position.mCurrent->_mPrev;
1525 0 : x->_mNext = position.mCurrent;
1526 0 : position.mCurrent->_mPrev->_mNext = x;
1527 0 : position.mCurrent->_mPrev = x;
1528 0 : return --position;
1529 : }
1530 :
1531 : // inserts x after position
1532 0 : iterator after_insert(iterator position, pointer x)
1533 : {
1534 : // use |mCurrent| to prevent DEBUG_PASS_END assertions
1535 0 : x->_mNext = position.mCurrent->_mNext;
1536 0 : x->_mPrev = position.mCurrent;
1537 0 : position.mCurrent->_mNext->_mPrev = x;
1538 0 : position.mCurrent->_mNext = x;
1539 0 : return ++position;
1540 : }
1541 :
1542 : // returns iterator pointing to after the element
1543 6 : iterator erase(iterator position)
1544 : // NOTE: leaves dangling next/prev pointers
1545 : {
1546 6 : position->_mPrev->_mNext = position->_mNext;
1547 6 : position->_mNext->_mPrev = position->_mPrev;
1548 6 : return ++position;
1549 : }
1550 :
1551 : void swap(self_type& y)
1552 : {
1553 : link_type tmp(y.mLink);
1554 : y.mLink = mLink;
1555 : mLink = tmp;
1556 :
1557 : if (!empty()) {
1558 : mLink._mNext->_mPrev = &mLink;
1559 : mLink._mPrev->_mNext = &mLink;
1560 : }
1561 :
1562 : if (!y.empty()) {
1563 : y.mLink._mNext->_mPrev = &y.mLink;
1564 : y.mLink._mPrev->_mNext = &y.mLink;
1565 : }
1566 : }
1567 :
1568 34 : void clear()
1569 : // NOTE: leaves dangling next/prev pointers
1570 : {
1571 34 : mLink._mNext = &mLink;
1572 34 : mLink._mPrev = &mLink;
1573 34 : }
1574 :
1575 : // inserts the conts of x before position and makes x empty
1576 0 : void splice(iterator position, self_type& x)
1577 : {
1578 : // use |mCurrent| to prevent DEBUG_PASS_END assertions
1579 0 : position.mCurrent->_mPrev->_mNext = x.mLink._mNext;
1580 0 : x.mLink._mNext->_mPrev = position.mCurrent->_mPrev;
1581 0 : x.mLink._mPrev->_mNext = position.mCurrent;
1582 0 : position.mCurrent->_mPrev = x.mLink._mPrev;
1583 0 : x.clear();
1584 0 : }
1585 :
1586 : // Inserts element *i from list x before position and removes
1587 : // it from x.
1588 : void splice(iterator position, self_type& x, iterator i)
1589 : {
1590 : NS_ASSERTION(!x.empty(), "Can't insert from empty list.");
1591 : NS_ASSERTION(position != i && position.mCurrent != i->_mNext,
1592 : "We don't check for this case.");
1593 :
1594 : // remove from |x|
1595 : i->_mPrev->_mNext = i->_mNext;
1596 : i->_mNext->_mPrev = i->_mPrev;
1597 :
1598 : // use |mCurrent| to prevent DEBUG_PASS_END assertions
1599 : // link into |this|, before-side
1600 : i->_mPrev = position.mCurrent->_mPrev;
1601 : position.mCurrent->_mPrev->_mNext = i.get();
1602 :
1603 : // link into |this|, after-side
1604 : i->_mNext = position.mCurrent;
1605 : position.mCurrent->_mPrev = i.get();
1606 : }
1607 :
1608 : // Inserts elements in [|first|, |last|), which are in |x|,
1609 : // into |this| before |position| and removes them from |x|.
1610 0 : void splice(iterator position, self_type& x, iterator first,
1611 : iterator last)
1612 : {
1613 0 : NS_ASSERTION(!x.empty(), "Can't insert from empty list.");
1614 :
1615 0 : if (first == last)
1616 0 : return;
1617 :
1618 0 : --last; // so we now want to move [first, last]
1619 : // remove from |x|
1620 0 : first->_mPrev->_mNext = last->_mNext;
1621 0 : last->_mNext->_mPrev = first->_mPrev;
1622 :
1623 : // use |mCurrent| to prevent DEBUG_PASS_END assertions
1624 : // link into |this|, before-side
1625 0 : first->_mPrev = position.mCurrent->_mPrev;
1626 0 : position.mCurrent->_mPrev->_mNext = first.get();
1627 :
1628 : // link into |this|, after-side
1629 0 : last->_mNext = position.mCurrent;
1630 0 : position.mCurrent->_mPrev = last.get();
1631 : }
1632 :
1633 : };
1634 :
1635 :
1636 : // Many of these implementations of operator= don't work yet. I don't
1637 : // know why.
1638 :
1639 : #ifdef DEBUG
1640 :
1641 : // NOTE: ASSIGN_FROM is meant to be used *only* as the entire body
1642 : // of a function and therefore lacks PR_{BEGIN,END}_MACRO
1643 : #define ASSIGN_FROM(other_) \
1644 : mCurrent = other_.mCurrent; \
1645 : mListLink = other_.mListLink; \
1646 : return *this;
1647 :
1648 : #else /* !NS_LINELIST_DEBUG_PASS_END */
1649 :
1650 : #define ASSIGN_FROM(other_) \
1651 : mCurrent = other_.mCurrent; \
1652 : return *this;
1653 :
1654 : #endif /* !NS_LINELIST_DEBUG_PASS_END */
1655 :
1656 : inline
1657 : nsLineList_iterator&
1658 516 : nsLineList_iterator::operator=(const nsLineList_iterator& aOther)
1659 : {
1660 516 : ASSIGN_FROM(aOther)
1661 : }
1662 :
1663 : inline
1664 : nsLineList_iterator&
1665 0 : nsLineList_iterator::operator=(const nsLineList_reverse_iterator& aOther)
1666 : {
1667 0 : ASSIGN_FROM(aOther)
1668 : }
1669 :
1670 : inline
1671 : nsLineList_reverse_iterator&
1672 : nsLineList_reverse_iterator::operator=(const nsLineList_iterator& aOther)
1673 : {
1674 : ASSIGN_FROM(aOther)
1675 : }
1676 :
1677 : inline
1678 : nsLineList_reverse_iterator&
1679 : nsLineList_reverse_iterator::operator=(const nsLineList_reverse_iterator& aOther)
1680 : {
1681 : ASSIGN_FROM(aOther)
1682 : }
1683 :
1684 : inline
1685 : nsLineList_const_iterator&
1686 : nsLineList_const_iterator::operator=(const nsLineList_iterator& aOther)
1687 : {
1688 : ASSIGN_FROM(aOther)
1689 : }
1690 :
1691 : inline
1692 : nsLineList_const_iterator&
1693 : nsLineList_const_iterator::operator=(const nsLineList_reverse_iterator& aOther)
1694 : {
1695 : ASSIGN_FROM(aOther)
1696 : }
1697 :
1698 : inline
1699 : nsLineList_const_iterator&
1700 : nsLineList_const_iterator::operator=(const nsLineList_const_iterator& aOther)
1701 : {
1702 : ASSIGN_FROM(aOther)
1703 : }
1704 :
1705 : inline
1706 : nsLineList_const_iterator&
1707 : nsLineList_const_iterator::operator=(const nsLineList_const_reverse_iterator& aOther)
1708 : {
1709 : ASSIGN_FROM(aOther)
1710 : }
1711 :
1712 : inline
1713 : nsLineList_const_reverse_iterator&
1714 : nsLineList_const_reverse_iterator::operator=(const nsLineList_iterator& aOther)
1715 : {
1716 : ASSIGN_FROM(aOther)
1717 : }
1718 :
1719 : inline
1720 : nsLineList_const_reverse_iterator&
1721 : nsLineList_const_reverse_iterator::operator=(const nsLineList_reverse_iterator& aOther)
1722 : {
1723 : ASSIGN_FROM(aOther)
1724 : }
1725 :
1726 : inline
1727 : nsLineList_const_reverse_iterator&
1728 : nsLineList_const_reverse_iterator::operator=(const nsLineList_const_iterator& aOther)
1729 : {
1730 : ASSIGN_FROM(aOther)
1731 : }
1732 :
1733 : inline
1734 : nsLineList_const_reverse_iterator&
1735 : nsLineList_const_reverse_iterator::operator=(const nsLineList_const_reverse_iterator& aOther)
1736 : {
1737 : ASSIGN_FROM(aOther)
1738 : }
1739 :
1740 :
1741 : //----------------------------------------------------------------------
1742 :
1743 : class nsLineIterator final : public nsILineIterator
1744 : {
1745 : public:
1746 : nsLineIterator();
1747 : ~nsLineIterator();
1748 :
1749 : virtual void DisposeLineIterator() override;
1750 :
1751 : virtual int32_t GetNumLines() override;
1752 : virtual bool GetDirection() override;
1753 : NS_IMETHOD GetLine(int32_t aLineNumber,
1754 : nsIFrame** aFirstFrameOnLine,
1755 : int32_t* aNumFramesOnLine,
1756 : nsRect& aLineBounds) override;
1757 : virtual int32_t FindLineContaining(nsIFrame* aFrame, int32_t aStartLine = 0) override;
1758 : NS_IMETHOD FindFrameAt(int32_t aLineNumber,
1759 : nsPoint aPos,
1760 : nsIFrame** aFrameFound,
1761 : bool* aPosIsBeforeFirstFrame,
1762 : bool* aPosIsAfterLastFrame) override;
1763 :
1764 : NS_IMETHOD GetNextSiblingOnLine(nsIFrame*& aFrame, int32_t aLineNumber) override;
1765 : NS_IMETHOD CheckLineOrder(int32_t aLine,
1766 : bool *aIsReordered,
1767 : nsIFrame **aFirstVisual,
1768 : nsIFrame **aLastVisual) override;
1769 : nsresult Init(nsLineList& aLines, bool aRightToLeft);
1770 :
1771 : private:
1772 : nsLineBox* PrevLine() {
1773 : if (0 == mIndex) {
1774 : return nullptr;
1775 : }
1776 : return mLines[--mIndex];
1777 : }
1778 :
1779 : nsLineBox* NextLine() {
1780 : if (mIndex >= mNumLines - 1) {
1781 : return nullptr;
1782 : }
1783 : return mLines[++mIndex];
1784 : }
1785 :
1786 : nsLineBox* LineAt(int32_t aIndex) {
1787 : if ((aIndex < 0) || (aIndex >= mNumLines)) {
1788 : return nullptr;
1789 : }
1790 : return mLines[aIndex];
1791 : }
1792 :
1793 : nsLineBox** mLines;
1794 : int32_t mIndex;
1795 : int32_t mNumLines;
1796 : bool mRightToLeft;
1797 : };
1798 :
1799 : #endif /* nsLineBox_h___ */
|