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 : /* class that manages rules for positioning floats */
8 :
9 : #ifndef nsFloatManager_h_
10 : #define nsFloatManager_h_
11 :
12 : #include "mozilla/Attributes.h"
13 : #include "mozilla/UniquePtr.h"
14 : #include "mozilla/WritingModes.h"
15 : #include "nsCoord.h"
16 : #include "nsFrameList.h" // for DEBUG_FRAME_DUMP
17 : #include "nsIntervalSet.h"
18 : #include "nsPoint.h"
19 : #include "nsTArray.h"
20 :
21 : class nsIPresShell;
22 : class nsIFrame;
23 : class nsPresContext;
24 : namespace mozilla {
25 : struct ReflowInput;
26 : class StyleBasicShape;
27 : } // namespace mozilla
28 :
29 : /**
30 : * The available space for content not occupied by floats is divided
31 : * into a sequence of rectangles in the block direction. However, we
32 : * need to know not only the rectangle, but also whether it was reduced
33 : * (from the content rectangle) by floats that actually intruded into
34 : * the content rectangle.
35 : */
36 235 : struct nsFlowAreaRect {
37 : mozilla::LogicalRect mRect;
38 : bool mHasFloats;
39 :
40 235 : nsFlowAreaRect(mozilla::WritingMode aWritingMode,
41 : nscoord aICoord, nscoord aBCoord,
42 : nscoord aISize, nscoord aBSize,
43 : bool aHasFloats)
44 235 : : mRect(aWritingMode, aICoord, aBCoord, aISize, aBSize)
45 235 : , mHasFloats(aHasFloats) {}
46 : };
47 :
48 : #define NS_FLOAT_MANAGER_CACHE_SIZE 64
49 :
50 : /**
51 : * nsFloatManager is responsible for implementing CSS's rules for
52 : * positioning floats. An nsFloatManager object is created during reflow for
53 : * any block with NS_BLOCK_FLOAT_MGR. During reflow, the float manager for
54 : * the nearest such ancestor block is found in ReflowInput::mFloatManager.
55 : *
56 : * According to the line-relative mappings in CSS Writing Modes spec [1],
57 : * line-right and line-left are calculated with respect to the writing mode
58 : * of the containing block of the floats. All the writing modes passed to
59 : * nsFloatManager methods should be the containing block's writing mode.
60 : *
61 : * However, according to the abstract-to-physical mappings table [2], the
62 : * 'direction' property of the containing block doesn't affect the
63 : * interpretation of line-right and line-left. We actually implement this by
64 : * passing in the writing mode of the block formatting context (BFC), i.e.
65 : * the of BlockReflowInput's writing mode.
66 : *
67 : * nsFloatManager uses a special logical coordinate space with inline
68 : * coordinates on the line-axis and block coordinates on the block-axis
69 : * based on the writing mode of the block formatting context. All the
70 : * physical types like nsRect, nsPoint, etc. use this coordinate space. See
71 : * FloatInfo::mRect for an example.
72 : *
73 : * [1] https://drafts.csswg.org/css-writing-modes/#line-mappings
74 : * [2] https://drafts.csswg.org/css-writing-modes/#logical-to-physical
75 : */
76 : class nsFloatManager {
77 : public:
78 : explicit nsFloatManager(nsIPresShell* aPresShell, mozilla::WritingMode aWM);
79 : ~nsFloatManager();
80 :
81 : void* operator new(size_t aSize) CPP_THROW_NEW;
82 : void operator delete(void* aPtr, size_t aSize);
83 :
84 : static void Shutdown();
85 :
86 : /**
87 : * Get float region stored on the frame. (Defaults to mRect if it's
88 : * not there.) The float region is the area impacted by this float;
89 : * the coordinates are relative to the containing block frame.
90 : */
91 : static mozilla::LogicalRect GetRegionFor(mozilla::WritingMode aWM,
92 : nsIFrame* aFloatFrame,
93 : const nsSize& aContainerSize);
94 : /**
95 : * Calculate the float region for this frame using aMargin and the
96 : * frame's mRect. The region includes the margins around the float,
97 : * but doesn't include the relative offsets.
98 : * Note that if the frame is or has a continuation, aMargin's top
99 : * and/or bottom must be zeroed by the caller.
100 : */
101 : static mozilla::LogicalRect CalculateRegionFor(
102 : mozilla::WritingMode aWM,
103 : nsIFrame* aFloatFrame,
104 : const mozilla::LogicalMargin& aMargin,
105 : const nsSize& aContainerSize);
106 : /**
107 : * Store the float region on the frame. The region is stored
108 : * as a delta against the mRect, so repositioning the frame will
109 : * also reposition the float region.
110 : */
111 : static void StoreRegionFor(mozilla::WritingMode aWM,
112 : nsIFrame* aFloat,
113 : const mozilla::LogicalRect& aRegion,
114 : const nsSize& aContainerSize);
115 :
116 : // Structure that stores the current state of a float manager for
117 : // Save/Restore purposes.
118 : struct SavedState {
119 247 : explicit SavedState() {}
120 : private:
121 : uint32_t mFloatInfoCount;
122 : nscoord mLineLeft, mBlockStart;
123 : bool mPushedLeftFloatPastBreak;
124 : bool mPushedRightFloatPastBreak;
125 : bool mSplitLeftFloatAcrossBreak;
126 : bool mSplitRightFloatAcrossBreak;
127 :
128 : friend class nsFloatManager;
129 : };
130 :
131 : /**
132 : * Translate the current origin by the specified offsets. This
133 : * creates a new local coordinate space relative to the current
134 : * coordinate space.
135 : */
136 170 : void Translate(nscoord aLineLeft, nscoord aBlockStart)
137 : {
138 170 : mLineLeft += aLineLeft;
139 170 : mBlockStart += aBlockStart;
140 170 : }
141 :
142 : /**
143 : * Returns the current translation from local coordinate space to
144 : * world coordinate space. This represents the accumulated calls to
145 : * Translate().
146 : */
147 397 : void GetTranslation(nscoord& aLineLeft, nscoord& aBlockStart) const
148 : {
149 397 : aLineLeft = mLineLeft;
150 397 : aBlockStart = mBlockStart;
151 397 : }
152 :
153 : /**
154 : * Get information about the area available to content that flows
155 : * around floats. Two different types of space can be requested:
156 : * BandFromPoint: returns the band containing block-dir coordinate
157 : * |aBCoord| (though actually with the top truncated to begin at
158 : * aBCoord), but up to at most |aBSize| (which may be nscoord_MAX).
159 : * This will return the tallest rectangle whose block start is
160 : * |aBCoord| and in which there are no changes in what floats are
161 : * on the sides of that rectangle, but will limit the block size
162 : * of the rectangle to |aBSize|. The inline start and end edges
163 : * of the rectangle give the area available for line boxes in that
164 : * space. The inline size of this resulting rectangle will not be
165 : * negative.
166 : * WidthWithinHeight: This returns a rectangle whose block start
167 : * is aBCoord and whose block size is exactly aBSize. Its inline
168 : * start and end edges give the corresponding edges of the space
169 : * that can be used for line boxes *throughout* that space. (It
170 : * is possible that more inline space could be used in part of the
171 : * space if a float begins or ends in it.) The inline size of the
172 : * resulting rectangle can be negative.
173 : *
174 : * ShapeType can be used to request two different types of flow areas.
175 : * (This is the float area defined in CSS Shapes Module Level 1 ยง1.4):
176 : * Margin: uses the float element's margin-box to request the flow area.
177 : * ShapeOutside: uses the float element's shape-outside value to request
178 : * the float area.
179 : *
180 : * @param aBCoord [in] block-dir coordinate for block start of available space
181 : * desired, which are positioned relative to the current translation.
182 : * @param aBSize [in] see above
183 : * @param aContentArea [in] an nsRect representing the content area
184 : * @param aState [in] If null, use the current state, otherwise, do
185 : * computation based only on floats present in the given
186 : * saved state.
187 : * @return An nsFlowAreaRect whose:
188 : * mRect is the resulting rectangle for line boxes. It will not
189 : * extend beyond aContentArea's inline bounds, but may be
190 : * narrower when floats are present.
191 : * mHasFloats is whether there are floats at the sides of the
192 : * return value including those that do not reduce the line box
193 : * inline size at all (because they are entirely in the margins)
194 : */
195 : enum class BandInfoType { BandFromPoint, WidthWithinHeight };
196 : enum class ShapeType { Margin, ShapeOutside };
197 : nsFlowAreaRect GetFlowArea(mozilla::WritingMode aWM,
198 : nscoord aBCoord, nscoord aBSize,
199 : BandInfoType aBandInfoType, ShapeType aShapeType,
200 : mozilla::LogicalRect aContentArea,
201 : SavedState* aState,
202 : const nsSize& aContainerSize) const;
203 :
204 : /**
205 : * Add a float that comes after all floats previously added. Its
206 : * block start must be even with or below the top of all previous
207 : * floats.
208 : *
209 : * aMarginRect is relative to the current translation. The caller
210 : * must ensure aMarginRect.height >= 0 and aMarginRect.width >= 0.
211 : */
212 : void AddFloat(nsIFrame* aFloatFrame,
213 : const mozilla::LogicalRect& aMarginRect,
214 : mozilla::WritingMode aWM, const nsSize& aContainerSize);
215 :
216 : /**
217 : * Notify that we tried to place a float that could not fit at all and
218 : * had to be pushed to the next page/column? (If so, we can't place
219 : * any more floats in this page/column because of the rule that the
220 : * top of a float cannot be above the top of an earlier float. It
221 : * also means that any clear needs to continue to the next column.)
222 : */
223 0 : void SetPushedLeftFloatPastBreak()
224 0 : { mPushedLeftFloatPastBreak = true; }
225 0 : void SetPushedRightFloatPastBreak()
226 0 : { mPushedRightFloatPastBreak = true; }
227 :
228 : /**
229 : * Notify that we split a float, with part of it needing to be pushed
230 : * to the next page/column. (This means that any 'clear' needs to
231 : * continue to the next page/column.)
232 : */
233 0 : void SetSplitLeftFloatAcrossBreak()
234 0 : { mSplitLeftFloatAcrossBreak = true; }
235 0 : void SetSplitRightFloatAcrossBreak()
236 0 : { mSplitRightFloatAcrossBreak = true; }
237 :
238 : /**
239 : * Remove the regions associated with this floating frame and its
240 : * next-sibling list. Some of the frames may never have been added;
241 : * we just skip those. This is not fully general; it only works as
242 : * long as the N frames to be removed are the last N frames to have
243 : * been added; if there's a frame in the middle of them that should
244 : * not be removed, YOU LOSE.
245 : */
246 : nsresult RemoveTrailingRegions(nsIFrame* aFrameList);
247 :
248 380 : bool HasAnyFloats() const { return !mFloats.IsEmpty(); }
249 :
250 : /**
251 : * Methods for dealing with the propagation of float damage during
252 : * reflow.
253 : */
254 0 : bool HasFloatDamage() const
255 : {
256 0 : return !mFloatDamage.IsEmpty();
257 : }
258 :
259 0 : void IncludeInDamage(nscoord aIntervalBegin, nscoord aIntervalEnd)
260 : {
261 0 : mFloatDamage.IncludeInterval(aIntervalBegin + mBlockStart,
262 0 : aIntervalEnd + mBlockStart);
263 0 : }
264 :
265 0 : bool IntersectsDamage(nscoord aIntervalBegin, nscoord aIntervalEnd) const
266 : {
267 0 : return mFloatDamage.Intersects(aIntervalBegin + mBlockStart,
268 0 : aIntervalEnd + mBlockStart);
269 : }
270 :
271 : /**
272 : * Saves the current state of the float manager into aState.
273 : */
274 : void PushState(SavedState* aState);
275 :
276 : /**
277 : * Restores the float manager to the saved state.
278 : *
279 : * These states must be managed using stack discipline. PopState can only
280 : * be used after PushState has been used to save the state, and it can only
281 : * be used once --- although it can be omitted; saved states can be ignored.
282 : * States must be popped in the reverse order they were pushed. A
283 : * call to PopState invalidates any saved states Pushed after the
284 : * state passed to PopState was pushed.
285 : */
286 : void PopState(SavedState* aState);
287 :
288 : /**
289 : * Get the block start of the last float placed into the float
290 : * manager, to enforce the rule that a float can't be above an earlier
291 : * float. Returns the minimum nscoord value if there are no floats.
292 : *
293 : * The result is relative to the current translation.
294 : */
295 : nscoord GetLowestFloatTop() const;
296 :
297 : /**
298 : * Return the coordinate of the lowest float matching aBreakType in
299 : * this float manager. Returns aBCoord if there are no matching
300 : * floats.
301 : *
302 : * Both aBCoord and the result are relative to the current translation.
303 : */
304 : enum {
305 : // Tell ClearFloats not to push to nscoord_MAX when floats have been
306 : // pushed to the next page/column.
307 : DONT_CLEAR_PUSHED_FLOATS = (1<<0)
308 : };
309 : nscoord ClearFloats(nscoord aBCoord, mozilla::StyleClear aBreakType,
310 : uint32_t aFlags = 0) const;
311 :
312 : /**
313 : * Checks if clear would pass into the floats' BFC's next-in-flow,
314 : * i.e. whether floats affecting this clear have continuations.
315 : */
316 : bool ClearContinues(mozilla::StyleClear aBreakType) const;
317 :
318 0 : void AssertStateMatches(SavedState *aState) const
319 : {
320 0 : NS_ASSERTION(aState->mLineLeft == mLineLeft &&
321 : aState->mBlockStart == mBlockStart &&
322 : aState->mPushedLeftFloatPastBreak ==
323 : mPushedLeftFloatPastBreak &&
324 : aState->mPushedRightFloatPastBreak ==
325 : mPushedRightFloatPastBreak &&
326 : aState->mSplitLeftFloatAcrossBreak ==
327 : mSplitLeftFloatAcrossBreak &&
328 : aState->mSplitRightFloatAcrossBreak ==
329 : mSplitRightFloatAcrossBreak &&
330 : aState->mFloatInfoCount == mFloats.Length(),
331 : "float manager state should match saved state");
332 0 : }
333 :
334 : #ifdef DEBUG_FRAME_DUMP
335 : /**
336 : * Dump the state of the float manager out to a file.
337 : */
338 : nsresult List(FILE* out) const;
339 : #endif
340 :
341 : private:
342 :
343 : // ShapeInfo is an abstract class for implementing all the shapes in CSS
344 : // Shapes Module. A subclass needs to override all the methods to adjust
345 : // the flow area with respect to its shape.
346 0 : class ShapeInfo
347 : {
348 : public:
349 0 : virtual ~ShapeInfo() {}
350 :
351 : virtual nscoord LineLeft(const nscoord aBStart,
352 : const nscoord aBEnd) const = 0;
353 : virtual nscoord LineRight(const nscoord aBStart,
354 : const nscoord aBEnd) const = 0;
355 : virtual nscoord BStart() const = 0;
356 : virtual nscoord BEnd() const = 0;
357 : virtual bool IsEmpty() const = 0;
358 :
359 : // Translate the current origin by the specified offsets.
360 : virtual void Translate(nscoord aLineLeft, nscoord aBlockStart) = 0;
361 :
362 : static mozilla::LogicalRect ComputeShapeBoxRect(
363 : const mozilla::StyleShapeSource& aShapeOutside,
364 : nsIFrame* const aFrame,
365 : const mozilla::LogicalRect& aMarginRect,
366 : mozilla::WritingMode aWM);
367 :
368 : // Convert the LogicalRect to the special logical coordinate space used
369 : // in float manager.
370 0 : static nsRect ConvertToFloatLogical(const mozilla::LogicalRect& aRect,
371 : mozilla::WritingMode aWM,
372 : const nsSize& aContainerSize)
373 : {
374 : return nsRect(aRect.LineLeft(aWM, aContainerSize), aRect.BStart(aWM),
375 0 : aRect.ISize(aWM), aRect.BSize(aWM));
376 : }
377 :
378 : static mozilla::UniquePtr<ShapeInfo> CreateShapeBox(
379 : nsIFrame* const aFrame,
380 : const mozilla::LogicalRect& aShapeBoxRect,
381 : mozilla::WritingMode aWM,
382 : const nsSize& aContainerSize);
383 :
384 : static mozilla::UniquePtr<ShapeInfo> CreateInset(
385 : const mozilla::StyleBasicShape* aBasicShape,
386 : const mozilla::LogicalRect& aShapeBoxRect,
387 : mozilla::WritingMode aWM,
388 : const nsSize& aContainerSize);
389 :
390 : static mozilla::UniquePtr<ShapeInfo> CreateCircleOrEllipse(
391 : const mozilla::StyleBasicShape* aBasicShape,
392 : const mozilla::LogicalRect& aShapeBoxRect,
393 : mozilla::WritingMode aWM,
394 : const nsSize& aContainerSize);
395 :
396 : static mozilla::UniquePtr<ShapeInfo> CreatePolygon(
397 : const mozilla::StyleBasicShape* aBasicShape,
398 : const mozilla::LogicalRect& aShapeBoxRect,
399 : mozilla::WritingMode aWM,
400 : const nsSize& aContainerSize);
401 :
402 : protected:
403 : // Compute the minimum line-axis difference between the bounding shape
404 : // box and its rounded corner within the given band (block-axis region).
405 : // This is used as a helper function to compute the LineRight() and
406 : // LineLeft(). See the picture in the implementation for an example.
407 : // RadiusL and RadiusB stand for radius on the line-axis and block-axis.
408 : //
409 : // Returns radius-x diff on the line-axis, or 0 if there's no rounded
410 : // corner within the given band.
411 : static nscoord ComputeEllipseLineInterceptDiff(
412 : const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
413 : const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
414 : const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,
415 : const nscoord aBandBStart, const nscoord aBandBEnd);
416 :
417 : static nscoord XInterceptAtY(const nscoord aY, const nscoord aRadiusX,
418 : const nscoord aRadiusY);
419 :
420 : // Convert the physical point to the special logical coordinate space
421 : // used in float manager.
422 : static nsPoint ConvertToFloatLogical(const nsPoint& aPoint,
423 : mozilla::WritingMode aWM,
424 : const nsSize& aContainerSize);
425 :
426 : // Convert the half corner radii (nscoord[8]) to the special logical
427 : // coordinate space used in float manager.
428 : static mozilla::UniquePtr<nscoord[]> ConvertToFloatLogical(
429 : const nscoord aRadii[8],
430 : mozilla::WritingMode aWM);
431 : };
432 :
433 : // Implements shape-outside: <shape-box> and shape-outside: inset().
434 0 : class RoundedBoxShapeInfo final : public ShapeInfo
435 : {
436 : public:
437 0 : RoundedBoxShapeInfo(const nsRect& aRect,
438 : mozilla::UniquePtr<nscoord[]> aRadii)
439 0 : : mRect(aRect)
440 0 : , mRadii(Move(aRadii))
441 0 : {}
442 :
443 : nscoord LineLeft(const nscoord aBStart,
444 : const nscoord aBEnd) const override;
445 : nscoord LineRight(const nscoord aBStart,
446 : const nscoord aBEnd) const override;
447 0 : nscoord BStart() const override { return mRect.y; }
448 0 : nscoord BEnd() const override { return mRect.YMost(); }
449 0 : bool IsEmpty() const override { return mRect.IsEmpty(); };
450 :
451 0 : void Translate(nscoord aLineLeft, nscoord aBlockStart) override
452 : {
453 0 : mRect.MoveBy(aLineLeft, aBlockStart);
454 0 : }
455 :
456 : private:
457 : // The rect of the rounded box shape in the float manager's coordinate
458 : // space.
459 : nsRect mRect;
460 : // The half corner radii of the reference box. It's an nscoord[8] array
461 : // in the float manager's coordinate space. If there are no radii, it's
462 : // nullptr.
463 : mozilla::UniquePtr<nscoord[]> mRadii;
464 : };
465 :
466 : // Implements shape-outside: circle() and shape-outside: ellipse().
467 0 : class EllipseShapeInfo final : public ShapeInfo
468 : {
469 : public:
470 0 : EllipseShapeInfo(const nsPoint& aCenter,
471 : const nsSize& aRadii)
472 0 : : mCenter(aCenter)
473 0 : , mRadii(aRadii)
474 0 : {}
475 :
476 : nscoord LineLeft(const nscoord aBStart,
477 : const nscoord aBEnd) const override;
478 : nscoord LineRight(const nscoord aBStart,
479 : const nscoord aBEnd) const override;
480 0 : nscoord BStart() const override { return mCenter.y - mRadii.height; }
481 0 : nscoord BEnd() const override { return mCenter.y + mRadii.height; }
482 0 : bool IsEmpty() const override { return mRadii.IsEmpty(); };
483 :
484 0 : void Translate(nscoord aLineLeft, nscoord aBlockStart) override
485 : {
486 0 : mCenter.MoveBy(aLineLeft, aBlockStart);
487 0 : }
488 :
489 : private:
490 : // The position of the center of the ellipse. The coordinate space is the
491 : // same as FloatInfo::mRect.
492 : nsPoint mCenter;
493 : // The radii of the ellipse in app units. The width and height represent
494 : // the line-axis and block-axis radii of the ellipse.
495 : nsSize mRadii;
496 : };
497 :
498 : // Implements shape-outside: polygon().
499 0 : class PolygonShapeInfo final : public ShapeInfo
500 : {
501 : public:
502 : explicit PolygonShapeInfo(nsTArray<nsPoint>&& aVertices);
503 :
504 : nscoord LineLeft(const nscoord aBStart,
505 : const nscoord aBEnd) const override;
506 : nscoord LineRight(const nscoord aBStart,
507 : const nscoord aBEnd) const override;
508 0 : nscoord BStart() const override { return mBStart; }
509 0 : nscoord BEnd() const override { return mBEnd; }
510 0 : bool IsEmpty() const override { return mEmpty; }
511 :
512 : void Translate(nscoord aLineLeft, nscoord aBlockStart) override;
513 :
514 : private:
515 : // Helper method for implementing LineLeft() and LineRight().
516 : nscoord ComputeLineIntercept(
517 : const nscoord aBStart,
518 : const nscoord aBEnd,
519 : nscoord (*aCompareOp) (std::initializer_list<nscoord>),
520 : const nscoord aLineInterceptInitialValue) const;
521 :
522 : // Given a horizontal line y, and two points p1 and p2 forming a line
523 : // segment L. Solve x for the intersection of y and L. This method
524 : // assumes y and L do intersect, and L is *not* horizontal.
525 : static nscoord XInterceptAtY(const nscoord aY,
526 : const nsPoint& aP1,
527 : const nsPoint& aP2);
528 :
529 : // The vertices of the polygon in the float manager's coordinate space.
530 : nsTArray<nsPoint> mVertices;
531 :
532 : // If mEmpty is true, that means the polygon encloses no area.
533 : bool mEmpty = false;
534 :
535 : // Computed block start and block end value of the polygon shape.
536 : //
537 : // If mEmpty is false, their initial values nscoord_MAX and nscoord_MIN
538 : // are used as sentinels for computing min() and max() in the
539 : // constructor, and mBStart is guaranteed to be less than or equal to
540 : // mBEnd. If mEmpty is true, their values do not matter.
541 : nscoord mBStart = nscoord_MAX;
542 : nscoord mBEnd = nscoord_MIN;
543 : };
544 :
545 : struct FloatInfo {
546 : nsIFrame *const mFrame;
547 : // The lowest block-ends of left/right floats up to and including
548 : // this one.
549 : nscoord mLeftBEnd, mRightBEnd;
550 :
551 : FloatInfo(nsIFrame* aFrame, nscoord aLineLeft, nscoord aBlockStart,
552 : const mozilla::LogicalRect& aMarginRect,
553 : mozilla::WritingMode aWM, const nsSize& aContainerSize);
554 :
555 0 : nscoord LineLeft() const { return mRect.x; }
556 0 : nscoord LineRight() const { return mRect.XMost(); }
557 0 : nscoord ISize() const { return mRect.width; }
558 0 : nscoord BStart() const { return mRect.y; }
559 0 : nscoord BEnd() const { return mRect.YMost(); }
560 0 : nscoord BSize() const { return mRect.height; }
561 0 : bool IsEmpty() const { return mRect.IsEmpty(); }
562 :
563 : // aBStart and aBEnd are the starting and ending coordinate of a band.
564 : // LineLeft() and LineRight() return the innermost line-left extent and
565 : // line-right extent within the given band, respectively.
566 : nscoord LineLeft(ShapeType aShapeType,
567 : const nscoord aBStart, const nscoord aBEnd) const;
568 : nscoord LineRight(ShapeType aShapeType,
569 : const nscoord aBStart, const nscoord aBEnd) const;
570 : nscoord BStart(ShapeType aShapeType) const;
571 : nscoord BEnd(ShapeType aShapeType) const;
572 : bool IsEmpty(ShapeType aShapeType) const;
573 :
574 : #ifdef NS_BUILD_REFCNT_LOGGING
575 : FloatInfo(FloatInfo&& aOther);
576 : ~FloatInfo();
577 : #endif
578 :
579 : // NB! This is really a logical rect in a writing mode suitable for
580 : // placing floats, which is not necessarily the actual writing mode
581 : // either of the block which created the float manager or the block
582 : // that is calling the float manager. The inline coordinates are in
583 : // the line-relative axis of the float manager and its block
584 : // coordinates are in the float manager's block direction.
585 : nsRect mRect;
586 : // Pointer to a concrete subclass of ShapeInfo or null, which means that
587 : // there is no shape-outside.
588 : mozilla::UniquePtr<ShapeInfo> mShapeInfo;
589 : };
590 :
591 : #ifdef DEBUG
592 : // Store the writing mode from the block frame which establishes the block
593 : // formatting context (BFC) when the nsFloatManager is created.
594 : mozilla::WritingMode mWritingMode;
595 : #endif
596 :
597 : // Translation from local to global coordinate space.
598 : nscoord mLineLeft, mBlockStart;
599 : // We use 11 here in order to fill up the jemalloc allocatoed chunk nicely,
600 : // see https://bugzilla.mozilla.org/show_bug.cgi?id=1362876#c6.
601 : AutoTArray<FloatInfo, 11> mFloats;
602 : nsIntervalSet mFloatDamage;
603 :
604 : // Did we try to place a float that could not fit at all and had to be
605 : // pushed to the next page/column? If so, we can't place any more
606 : // floats in this page/column because of the rule that the top of a
607 : // float cannot be above the top of an earlier float. And we also
608 : // need to apply this information to 'clear', and thus need to
609 : // separate left and right floats.
610 : bool mPushedLeftFloatPastBreak;
611 : bool mPushedRightFloatPastBreak;
612 :
613 : // Did we split a float, with part of it needing to be pushed to the
614 : // next page/column. This means that any 'clear' needs to continue to
615 : // the next page/column.
616 : bool mSplitLeftFloatAcrossBreak;
617 : bool mSplitRightFloatAcrossBreak;
618 :
619 : static int32_t sCachedFloatManagerCount;
620 : static void* sCachedFloatManagers[NS_FLOAT_MANAGER_CACHE_SIZE];
621 :
622 : nsFloatManager(const nsFloatManager&) = delete;
623 : void operator=(const nsFloatManager&) = delete;
624 : };
625 :
626 : /**
627 : * A helper class to manage maintenance of the float manager during
628 : * nsBlockFrame::Reflow. It automatically restores the old float
629 : * manager in the reflow input when the object goes out of scope.
630 : */
631 : class nsAutoFloatManager {
632 : using ReflowInput = mozilla::ReflowInput;
633 :
634 : public:
635 162 : explicit nsAutoFloatManager(ReflowInput& aReflowInput)
636 162 : : mReflowInput(aReflowInput)
637 162 : , mOld(nullptr)
638 162 : {}
639 :
640 : ~nsAutoFloatManager();
641 :
642 : /**
643 : * Create a new float manager for the specified frame. This will
644 : * `remember' the old float manager, and install the new float
645 : * manager in the reflow input.
646 : */
647 : void
648 : CreateFloatManager(nsPresContext *aPresContext);
649 :
650 : protected:
651 : ReflowInput &mReflowInput;
652 : mozilla::UniquePtr<nsFloatManager> mNew;
653 :
654 : // A non-owning pointer, which points to the object owned by
655 : // nsAutoFloatManager::mNew.
656 : nsFloatManager* mOld;
657 : };
658 :
659 : #endif /* !defined(nsFloatManager_h_) */
|