Line data Source code
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 : /* base class of all rendering objects */
8 :
9 : #ifndef nsFrame_h___
10 : #define nsFrame_h___
11 :
12 : #include "mozilla/Attributes.h"
13 : #include "mozilla/EventForwards.h"
14 : #include "mozilla/Likely.h"
15 : #include "nsBox.h"
16 : #include "mozilla/Logging.h"
17 :
18 : #include "nsIPresShell.h"
19 : #include "mozilla/ReflowInput.h"
20 : #include "nsHTMLParts.h"
21 : #include "nsISelectionDisplay.h"
22 :
23 : namespace mozilla {
24 : enum class TableSelection : uint32_t;
25 : } // namespace mozilla
26 :
27 : /**
28 : * nsFrame logging constants. We redefine the nspr
29 : * PRLogModuleInfo.level field to be a bitfield. Each bit controls a
30 : * specific type of logging. Each logging operation has associated
31 : * inline methods defined below.
32 : *
33 : * Due to the redefinition of the level field we cannot use MOZ_LOG directly
34 : * as that will cause assertions due to invalid log levels.
35 : */
36 : #define NS_FRAME_TRACE_CALLS 0x1
37 : #define NS_FRAME_TRACE_PUSH_PULL 0x2
38 : #define NS_FRAME_TRACE_CHILD_REFLOW 0x4
39 : #define NS_FRAME_TRACE_NEW_FRAMES 0x8
40 :
41 : #define NS_FRAME_LOG_TEST(_lm,_bit) (int(((mozilla::LogModule*)_lm)->Level()) & (_bit))
42 :
43 : #ifdef DEBUG
44 : #define NS_FRAME_LOG(_bit,_args) \
45 : PR_BEGIN_MACRO \
46 : if (NS_FRAME_LOG_TEST(nsFrame::sFrameLogModule,_bit)) { \
47 : printf_stderr _args; \
48 : } \
49 : PR_END_MACRO
50 : #else
51 : #define NS_FRAME_LOG(_bit,_args)
52 : #endif
53 :
54 : // XXX Need to rework this so that logging is free when it's off
55 : #ifdef DEBUG
56 : #define NS_FRAME_TRACE_IN(_method) Trace(_method, true)
57 :
58 : #define NS_FRAME_TRACE_OUT(_method) Trace(_method, false)
59 :
60 : // XXX remove me
61 : #define NS_FRAME_TRACE_MSG(_bit,_args) \
62 : PR_BEGIN_MACRO \
63 : if (NS_FRAME_LOG_TEST(nsFrame::sFrameLogModule,_bit)) { \
64 : TraceMsg _args; \
65 : } \
66 : PR_END_MACRO
67 :
68 : #define NS_FRAME_TRACE(_bit,_args) \
69 : PR_BEGIN_MACRO \
70 : if (NS_FRAME_LOG_TEST(nsFrame::sFrameLogModule,_bit)) { \
71 : TraceMsg _args; \
72 : } \
73 : PR_END_MACRO
74 :
75 : #define NS_FRAME_TRACE_REFLOW_IN(_method) Trace(_method, true)
76 :
77 : #define NS_FRAME_TRACE_REFLOW_OUT(_method, _status) \
78 : Trace(_method, false, _status)
79 :
80 : #else
81 : #define NS_FRAME_TRACE(_bits,_args)
82 : #define NS_FRAME_TRACE_IN(_method)
83 : #define NS_FRAME_TRACE_OUT(_method)
84 : #define NS_FRAME_TRACE_MSG(_bits,_args)
85 : #define NS_FRAME_TRACE_REFLOW_IN(_method)
86 : #define NS_FRAME_TRACE_REFLOW_OUT(_method, _status)
87 : #endif
88 :
89 : // Frame allocation boilerplate macros. Every subclass of nsFrame must
90 : // either use NS_{DECL,IMPL}_FRAMEARENA_HELPERS pair for allocating
91 : // memory correctly, or use NS_DECL_ABSTRACT_FRAME to declare a frame
92 : // class abstract and stop it from being instantiated. If a frame class
93 : // without its own operator new and GetFrameId gets instantiated, the
94 : // per-frame recycler lists in nsPresArena will not work correctly,
95 : // with potentially catastrophic consequences (not enough memory is
96 : // allocated for a frame object).
97 :
98 : #define NS_DECL_FRAMEARENA_HELPERS(class) \
99 : NS_DECL_QUERYFRAME_TARGET(class) \
100 : static constexpr nsIFrame::ClassID kClassID = nsIFrame::ClassID::class##_id; \
101 : void* operator new(size_t, nsIPresShell*) MOZ_MUST_OVERRIDE; \
102 : nsQueryFrame::FrameIID GetFrameId() override MOZ_MUST_OVERRIDE { \
103 : return nsQueryFrame::class##_id; \
104 : }
105 :
106 : #define NS_IMPL_FRAMEARENA_HELPERS(class) \
107 : void* class::operator new(size_t sz, nsIPresShell* aShell) \
108 : { return aShell->AllocateFrame(nsQueryFrame::class##_id, sz); } \
109 :
110 : #define NS_DECL_ABSTRACT_FRAME(class) \
111 : void* operator new(size_t, nsIPresShell*) MOZ_MUST_OVERRIDE = delete; \
112 : virtual nsQueryFrame::FrameIID GetFrameId() override MOZ_MUST_OVERRIDE = 0;
113 :
114 : //----------------------------------------------------------------------
115 :
116 : struct nsBoxLayoutMetrics;
117 : struct nsRect;
118 :
119 : /**
120 : * Implementation of a simple frame that's not splittable and has no
121 : * child frames.
122 : *
123 : * Sets the NS_FRAME_SYNCHRONIZE_FRAME_AND_VIEW bit, so the default
124 : * behavior is to keep the frame and view position and size in sync.
125 : */
126 : class nsFrame : public nsBox
127 : {
128 : public:
129 : /**
130 : * Create a new "empty" frame that maps a given piece of content into a
131 : * 0,0 area.
132 : */
133 : friend nsIFrame* NS_NewEmptyFrame(nsIPresShell* aShell,
134 : ComputedStyle* aStyle);
135 :
136 : private:
137 : // Left undefined; nsFrame objects are never allocated from the heap.
138 : void* operator new(size_t sz) CPP_THROW_NEW;
139 :
140 : protected:
141 : // Overridden to prevent the global delete from being called, since
142 : // the memory came out of an arena instead of the heap.
143 : //
144 : // Ideally this would be private and undefined, like the normal
145 : // operator new. Unfortunately, the C++ standard requires an
146 : // overridden operator delete to be accessible to any subclass that
147 : // defines a virtual destructor, so we can only make it protected;
148 : // worse, some C++ compilers will synthesize calls to this function
149 : // from the "deleting destructors" that they emit in case of
150 : // delete-expressions, so it can't even be undefined.
151 : void operator delete(void* aPtr, size_t sz);
152 :
153 : public:
154 :
155 : // nsQueryFrame
156 : NS_DECL_QUERYFRAME
157 : NS_DECL_QUERYFRAME_TARGET(nsFrame)
158 0 : virtual nsQueryFrame::FrameIID GetFrameId() MOZ_MUST_OVERRIDE {
159 0 : return kFrameIID;
160 : }
161 : void* operator new(size_t, nsIPresShell*) MOZ_MUST_OVERRIDE;
162 :
163 : // nsIFrame
164 : void Init(nsIContent* aContent,
165 : nsContainerFrame* aParent,
166 : nsIFrame* aPrevInFlow) override;
167 : void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override;
168 : ComputedStyle* GetAdditionalComputedStyle(int32_t aIndex) const override;
169 : void SetAdditionalComputedStyle(int32_t aIndex,
170 : ComputedStyle* aComputedStyle) override;
171 : nscoord GetLogicalBaseline(mozilla::WritingMode aWritingMode) const override;
172 : const nsFrameList& GetChildList(ChildListID aListID) const override;
173 : void GetChildLists(nsTArray<ChildList>* aLists) const override;
174 :
175 : nsresult HandleEvent(nsPresContext* aPresContext,
176 : mozilla::WidgetGUIEvent* aEvent,
177 : nsEventStatus* aEventStatus) override;
178 : nsresult GetContentForEvent(mozilla::WidgetEvent* aEvent,
179 : nsIContent** aContent) override;
180 : nsresult GetCursor(const nsPoint& aPoint,
181 : nsIFrame::Cursor& aCursor) override;
182 :
183 : nsresult GetPointFromOffset(int32_t inOffset,
184 : nsPoint* outPoint) override;
185 : nsresult GetCharacterRectsInRange(int32_t aInOffset,
186 : int32_t aLength,
187 : nsTArray<nsRect>& aOutRect) override;
188 :
189 : nsresult GetChildFrameContainingOffset(int32_t inContentOffset,
190 : bool inHint,
191 : int32_t* outFrameContentOffset,
192 : nsIFrame** outChildFrame) override;
193 :
194 : static nsresult GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
195 : nsPeekOffsetStruct *aPos,
196 : nsIFrame *aBlockFrame,
197 : int32_t aLineStart,
198 : int8_t aOutSideLimit);
199 :
200 : nsresult CharacterDataChanged(const CharacterDataChangeInfo& aInfo) override;
201 : nsresult AttributeChanged(int32_t aNameSpaceID,
202 : nsAtom* aAttribute,
203 : int32_t aModType) override;
204 : nsSplittableType GetSplittableType() const override;
205 : nsIFrame* GetPrevContinuation() const override;
206 : void SetPrevContinuation(nsIFrame*) override;
207 : nsIFrame* GetNextContinuation() const override;
208 : void SetNextContinuation(nsIFrame*) override;
209 : nsIFrame* GetPrevInFlowVirtual() const override;
210 : void SetPrevInFlow(nsIFrame*) override;
211 : nsIFrame* GetNextInFlowVirtual() const override;
212 : void SetNextInFlow(nsIFrame*) override;
213 :
214 : nsresult GetSelectionController(nsPresContext *aPresContext,
215 : nsISelectionController **aSelCon) override;
216 :
217 : FrameSearchResult PeekOffsetNoAmount(bool aForward,
218 : int32_t* aOffset) override;
219 : FrameSearchResult
220 : PeekOffsetCharacter(bool aForward, int32_t* aOffset,
221 : PeekOffsetCharacterOptions aOptions =
222 : PeekOffsetCharacterOptions()) override;
223 : FrameSearchResult PeekOffsetWord(bool aForward, bool aWordSelectEatSpace,
224 : bool aIsKeyboardSelect,
225 : int32_t* aOffset,
226 : PeekWordState *aState) override;
227 : /**
228 : * Check whether we should break at a boundary between punctuation and
229 : * non-punctuation. Only call it at a punctuation boundary
230 : * (i.e. exactly one of the previous and next characters are punctuation).
231 : * @param aForward true if we're moving forward in content order
232 : * @param aPunctAfter true if the next character is punctuation
233 : * @param aWhitespaceAfter true if the next character is whitespace
234 : */
235 : bool BreakWordBetweenPunctuation(const PeekWordState* aState,
236 : bool aForward,
237 : bool aPunctAfter, bool aWhitespaceAfter,
238 : bool aIsKeyboardSelect);
239 :
240 : nsresult CheckVisibility(nsPresContext* aContext,
241 : int32_t aStartIndex, int32_t aEndIndex,
242 : bool aRecurse, bool *aFinished,
243 : bool *_retval) override;
244 :
245 : nsresult GetOffsets(int32_t &aStart, int32_t &aEnd) const override;
246 : void ChildIsDirty(nsIFrame* aChild) override;
247 :
248 : #ifdef ACCESSIBILITY
249 : mozilla::a11y::AccType AccessibleType() override;
250 : #endif
251 :
252 0 : ComputedStyle* GetParentComputedStyle(nsIFrame** aProviderFrame) const override {
253 0 : return DoGetParentComputedStyle(aProviderFrame);
254 : }
255 :
256 : /**
257 : * Do the work for getting the parent ComputedStyle frame so that
258 : * other frame's |GetParentComputedStyle| methods can call this
259 : * method on *another* frame. (This function handles out-of-flow
260 : * frames by using the frame manager's placeholder map and it also
261 : * handles block-within-inline and generated content wrappers.)
262 : *
263 : * @param aProviderFrame (out) the frame associated with the returned value
264 : * or null if the ComputedStyle is for display:contents content.
265 : * @return The ComputedStyle that should be the parent of this frame's
266 : * ComputedStyle. Null is permitted, and means that this frame's
267 : * ComputedStyle should be the root of the ComputedStyle tree.
268 : */
269 : ComputedStyle* DoGetParentComputedStyle(nsIFrame** aProviderFrame) const;
270 :
271 : bool IsEmpty() override;
272 : bool IsSelfEmpty() override;
273 :
274 : void MarkIntrinsicISizesDirty() override;
275 : nscoord GetMinISize(gfxContext *aRenderingContext) override;
276 : nscoord GetPrefISize(gfxContext *aRenderingContext) override;
277 : void AddInlineMinISize(gfxContext *aRenderingContext,
278 : InlineMinISizeData *aData) override;
279 : void AddInlinePrefISize(gfxContext *aRenderingContext,
280 : InlinePrefISizeData *aData) override;
281 : IntrinsicISizeOffsetData
282 : IntrinsicISizeOffsets(nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE) override;
283 : mozilla::IntrinsicSize GetIntrinsicSize() override;
284 : nsSize GetIntrinsicRatio() override;
285 :
286 : mozilla::LogicalSize
287 : ComputeSize(gfxContext* aRenderingContext,
288 : mozilla::WritingMode aWM,
289 : const mozilla::LogicalSize& aCBSize,
290 : nscoord aAvailableISize,
291 : const mozilla::LogicalSize& aMargin,
292 : const mozilla::LogicalSize& aBorder,
293 : const mozilla::LogicalSize& aPadding,
294 : ComputeSizeFlags aFlags) override;
295 :
296 : /**
297 : * Calculate the used values for 'width' and 'height' for a replaced element.
298 : * http://www.w3.org/TR/CSS21/visudet.html#min-max-widths
299 : */
300 : mozilla::LogicalSize
301 : ComputeSizeWithIntrinsicDimensions(
302 : gfxContext* aRenderingContext,
303 : mozilla::WritingMode aWM,
304 : const mozilla::IntrinsicSize& aIntrinsicSize,
305 : nsSize aIntrinsicRatio,
306 : const mozilla::LogicalSize& aCBSize,
307 : const mozilla::LogicalSize& aMargin,
308 : const mozilla::LogicalSize& aBorder,
309 : const mozilla::LogicalSize& aPadding,
310 : ComputeSizeFlags aFlags);
311 :
312 : // Compute tight bounds assuming this frame honours its border, background
313 : // and outline, its children's tight bounds, and nothing else.
314 : nsRect ComputeSimpleTightBounds(mozilla::gfx::DrawTarget* aDrawTarget) const;
315 :
316 : /**
317 : * A helper, used by |nsFrame::ComputeSize| (for frames that need to
318 : * override only this part of ComputeSize), that computes the size
319 : * that should be returned when 'width', 'height', and
320 : * min/max-width/height are all 'auto' or equivalent.
321 : *
322 : * In general, frames that can accept any computed width/height should
323 : * override only ComputeAutoSize, and frames that cannot do so need to
324 : * override ComputeSize to enforce their width/height invariants.
325 : *
326 : * Implementations may optimize by returning a garbage width if
327 : * StylePosition()->mWidth.GetUnit() != eStyleUnit_Auto, and
328 : * likewise for height, since in such cases the result is guaranteed
329 : * to be unused.
330 : */
331 : virtual mozilla::LogicalSize
332 : ComputeAutoSize(gfxContext* aRenderingContext,
333 : mozilla::WritingMode aWM,
334 : const mozilla::LogicalSize& aCBSize,
335 : nscoord aAvailableISize,
336 : const mozilla::LogicalSize& aMargin,
337 : const mozilla::LogicalSize& aBorder,
338 : const mozilla::LogicalSize& aPadding,
339 : ComputeSizeFlags aFlags);
340 :
341 : /**
342 : * Utility function for ComputeAutoSize implementations. Return
343 : * max(GetMinISize(), min(aISizeInCB, GetPrefISize()))
344 : */
345 : nscoord ShrinkWidthToFit(gfxContext* aRenderingContext,
346 : nscoord aISizeInCB,
347 : ComputeSizeFlags aFlags);
348 :
349 : /**
350 : * Calculates the size of this frame after reflowing (calling Reflow on, and
351 : * updating the size and position of) its children, as necessary. The
352 : * calculated size is returned to the caller via the ReflowOutput
353 : * outparam. (The caller is responsible for setting the actual size and
354 : * position of this frame.)
355 : *
356 : * A frame's children must _all_ be reflowed if the frame is dirty (the
357 : * NS_FRAME_IS_DIRTY bit is set on it). Otherwise, individual children
358 : * must be reflowed if they are dirty or have the NS_FRAME_HAS_DIRTY_CHILDREN
359 : * bit set on them. Otherwise, whether children need to be reflowed depends
360 : * on the frame's type (it's up to individual Reflow methods), and on what
361 : * has changed. For example, a change in the width of the frame may require
362 : * all of its children to be reflowed (even those without dirty bits set on
363 : * them), whereas a change in its height might not.
364 : * (ReflowInput::ShouldReflowAllKids may be helpful in deciding whether
365 : * to reflow all the children, but for some frame types it might result in
366 : * over-reflow.)
367 : *
368 : * Note: if it's only the overflow rect(s) of a frame that need to be
369 : * updated, then UpdateOverflow should be called instead of Reflow.
370 : */
371 : void Reflow(nsPresContext* aPresContext,
372 : ReflowOutput& aDesiredSize,
373 : const ReflowInput& aReflowInput,
374 : nsReflowStatus& aStatus) override;
375 : void DidReflow(nsPresContext* aPresContext,
376 : const ReflowInput* aReflowInput) override;
377 :
378 : /**
379 : * NOTE: aStatus is assumed to be already-initialized. The reflow statuses of
380 : * any reflowed absolute children will be merged into aStatus; aside from
381 : * that, this method won't modify aStatus.
382 : */
383 : void ReflowAbsoluteFrames(nsPresContext* aPresContext,
384 : ReflowOutput& aDesiredSize,
385 : const ReflowInput& aReflowInput,
386 : nsReflowStatus& aStatus,
387 : bool aConstrainBSize = true);
388 : void FinishReflowWithAbsoluteFrames(nsPresContext* aPresContext,
389 : ReflowOutput& aDesiredSize,
390 : const ReflowInput& aReflowInput,
391 : nsReflowStatus& aStatus,
392 : bool aConstrainBSize = true);
393 :
394 : /*
395 : * If this frame is dirty, marks all absolutely-positioned children of this
396 : * frame dirty. If this frame isn't dirty, or if there are no
397 : * absolutely-positioned children, does nothing.
398 : *
399 : * It's necessary to use PushDirtyBitToAbsoluteFrames() when you plan to
400 : * reflow this frame's absolutely-positioned children after the dirty bit on
401 : * this frame has already been cleared, which prevents ReflowInput from
402 : * propagating the dirty bit normally. This situation generally only arises
403 : * when a multipass layout algorithm is used.
404 : */
405 : void PushDirtyBitToAbsoluteFrames();
406 :
407 : bool CanContinueTextRun() const override;
408 :
409 : bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) override;
410 :
411 : void UnionChildOverflow(nsOverflowAreas& aOverflowAreas) override;
412 :
413 : // Selection Methods
414 :
415 : NS_IMETHOD HandlePress(nsPresContext* aPresContext,
416 : mozilla::WidgetGUIEvent* aEvent,
417 : nsEventStatus* aEventStatus);
418 :
419 : NS_IMETHOD HandleMultiplePress(nsPresContext* aPresContext,
420 : mozilla::WidgetGUIEvent* aEvent,
421 : nsEventStatus* aEventStatus,
422 : bool aControlHeld);
423 :
424 : NS_IMETHOD HandleDrag(nsPresContext* aPresContext,
425 : mozilla::WidgetGUIEvent* aEvent,
426 : nsEventStatus* aEventStatus);
427 :
428 : NS_IMETHOD HandleRelease(nsPresContext* aPresContext,
429 : mozilla::WidgetGUIEvent* aEvent,
430 : nsEventStatus* aEventStatus);
431 :
432 : enum { SELECT_ACCUMULATE = 0x01 };
433 :
434 : nsresult PeekBackwardAndForward(nsSelectionAmount aAmountBack,
435 : nsSelectionAmount aAmountForward,
436 : int32_t aStartPos,
437 : bool aJumpLines,
438 : uint32_t aSelectFlags);
439 :
440 : nsresult SelectByTypeAtPoint(nsPresContext* aPresContext,
441 : const nsPoint& aPoint,
442 : nsSelectionAmount aBeginAmountType,
443 : nsSelectionAmount aEndAmountType,
444 : uint32_t aSelectFlags);
445 :
446 : // Helper for GetContentAndOffsetsFromPoint; calculation of content offsets
447 : // in this function assumes there is no child frame that can be targeted.
448 : virtual ContentOffsets CalcContentOffsetsFromFramePoint(const nsPoint& aPoint);
449 :
450 : // Box layout methods
451 : nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) override;
452 : nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
453 : nsSize GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState) override;
454 : nscoord GetXULFlex() override;
455 : nscoord GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState) override;
456 :
457 : // We compute and store the HTML content's overflow area. So don't
458 : // try to compute it in the box code.
459 0 : bool ComputesOwnOverflowArea() override { return true; }
460 :
461 : //--------------------------------------------------
462 : // Additional methods
463 :
464 : // Helper function that tests if the frame tree is too deep; if it is
465 : // it marks the frame as "unflowable", zeroes out the metrics, sets
466 : // the reflow status, and returns true. Otherwise, the frame is
467 : // unmarked "unflowable" and the metrics and reflow status are not
468 : // touched and false is returned.
469 : bool IsFrameTreeTooDeep(const ReflowInput& aReflowInput,
470 : ReflowOutput& aMetrics,
471 : nsReflowStatus& aStatus);
472 :
473 : // Incorporate the child overflow areas into aOverflowAreas.
474 : // If the child does not have a overflow, use the child area.
475 : void ConsiderChildOverflow(nsOverflowAreas& aOverflowAreas,
476 : nsIFrame* aChildFrame);
477 :
478 : /**
479 : * @return true if we should avoid a page/column break in this frame.
480 : */
481 : bool ShouldAvoidBreakInside(const ReflowInput& aReflowInput) const;
482 :
483 : #ifdef DEBUG
484 : /**
485 : * Tracing method that writes a method enter/exit routine to the
486 : * nspr log using the nsIFrame log module. The tracing is only
487 : * done when the NS_FRAME_TRACE_CALLS bit is set in the log module's
488 : * level field.
489 : */
490 : void Trace(const char* aMethod, bool aEnter);
491 : void Trace(const char* aMethod, bool aEnter, const nsReflowStatus& aStatus);
492 : void TraceMsg(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
493 :
494 : // Helper function that verifies that each frame in the list has the
495 : // NS_FRAME_IS_DIRTY bit set
496 : static void VerifyDirtyBitSet(const nsFrameList& aFrameList);
497 :
498 : // Display Reflow Debugging
499 : static void* DisplayReflowEnter(nsPresContext* aPresContext,
500 : nsIFrame* aFrame,
501 : const ReflowInput& aReflowInput);
502 : static void* DisplayLayoutEnter(nsIFrame* aFrame);
503 : static void* DisplayIntrinsicISizeEnter(nsIFrame* aFrame,
504 : const char* aType);
505 : static void* DisplayIntrinsicSizeEnter(nsIFrame* aFrame,
506 : const char* aType);
507 : static void DisplayReflowExit(nsPresContext* aPresContext,
508 : nsIFrame* aFrame,
509 : ReflowOutput& aMetrics,
510 : const nsReflowStatus& aStatus,
511 : void* aFrameTreeNode);
512 : static void DisplayLayoutExit(nsIFrame* aFrame,
513 : void* aFrameTreeNode);
514 : static void DisplayIntrinsicISizeExit(nsIFrame* aFrame,
515 : const char* aType,
516 : nscoord aResult,
517 : void* aFrameTreeNode);
518 : static void DisplayIntrinsicSizeExit(nsIFrame* aFrame,
519 : const char* aType,
520 : nsSize aResult,
521 : void* aFrameTreeNode);
522 :
523 : static void DisplayReflowStartup();
524 : static void DisplayReflowShutdown();
525 : #endif
526 :
527 : /**
528 : * Adds display items for standard CSS background if necessary.
529 : * Does not check IsVisibleForPainting.
530 : * @param aForceBackground draw the background even if the frame
531 : * background style appears to have no background --- this is useful
532 : * for frames that might receive a propagated background via
533 : * nsCSSRendering::FindBackground
534 : * @return whether a themed background item was created.
535 : */
536 : bool DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
537 : const nsDisplayListSet& aLists,
538 : bool aForceBackground);
539 : /**
540 : * Adds display items for standard CSS borders, background and outline for
541 : * for this frame, as necessary. Checks IsVisibleForPainting and won't
542 : * display anything if the frame is not visible.
543 : * @param aForceBackground draw the background even if the frame
544 : * background style appears to have no background --- this is useful
545 : * for frames that might receive a propagated background via
546 : * nsCSSRendering::FindBackground
547 : */
548 : void DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
549 : const nsDisplayListSet& aLists,
550 : bool aForceBackground = false);
551 : /**
552 : * Add a display item for the CSS outline. Does not check visibility.
553 : */
554 : void DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder,
555 : const nsDisplayListSet& aLists);
556 : /**
557 : * Add a display item for the CSS outline, after calling
558 : * IsVisibleForPainting to confirm we are visible.
559 : */
560 : void DisplayOutline(nsDisplayListBuilder* aBuilder,
561 : const nsDisplayListSet& aLists);
562 :
563 : /**
564 : * Adjust the given parent frame to the right ComputedStyle parent frame for
565 : * the child, given the pseudo-type of the prospective child. This handles
566 : * things like walking out of table pseudos and so forth.
567 : *
568 : * @param aProspectiveParent what GetParent() on the child returns.
569 : * Must not be null.
570 : * @param aChildPseudo the child's pseudo type, if any.
571 : */
572 : static nsIFrame*
573 : CorrectStyleParentFrame(nsIFrame* aProspectiveParent, nsAtom* aChildPseudo);
574 :
575 : protected:
576 : // Protected constructor and destructor
577 : nsFrame(ComputedStyle* aStyle, ClassID aID);
578 0 : explicit nsFrame(ComputedStyle* aStyle)
579 0 : : nsFrame(aStyle, ClassID::nsFrame_id) {}
580 : virtual ~nsFrame();
581 :
582 : /**
583 : * To be called by |BuildDisplayLists| of this class or derived classes to add
584 : * a translucent overlay if this frame's content is selected.
585 : * @param aContentType an nsISelectionDisplay DISPLAY_ constant identifying
586 : * which kind of content this is for
587 : */
588 : void DisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
589 : nsDisplayList* aList, uint16_t aContentType = nsISelectionDisplay::DISPLAY_FRAMES);
590 :
591 : int16_t DisplaySelection(nsPresContext* aPresContext, bool isOkToTurnOn = false);
592 :
593 : // Style post processing hook
594 : void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override;
595 :
596 : public:
597 : /**
598 : * Helper method to create a view for a frame. Only used by a few sub-classes
599 : * that need a view.
600 : */
601 : void CreateView();
602 :
603 : //given a frame five me the first/last leaf available
604 : //XXX Robert O'Callahan wants to move these elsewhere
605 : static void GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame);
606 : static void GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame);
607 :
608 : // Return the line number of the aFrame, and (optionally) the containing block
609 : // frame.
610 : // If aScrollLock is true, don't break outside scrollframes when looking for a
611 : // containing block frame.
612 : static int32_t GetLineNumber(nsIFrame *aFrame,
613 : bool aLockScroll,
614 : nsIFrame** aContainingBlock = nullptr);
615 :
616 : /**
617 : * Returns true if aFrame should apply overflow clipping.
618 : */
619 0 : static bool ShouldApplyOverflowClipping(const nsIFrame* aFrame,
620 : const nsStyleDisplay* aDisp)
621 : {
622 : // clip overflow:-moz-hidden-unscrollable, except for nsListControlFrame,
623 : // which is an nsHTMLScrollFrame.
624 0 : if (MOZ_UNLIKELY(aDisp->mOverflowX == NS_STYLE_OVERFLOW_CLIP &&
625 : !aFrame->IsListControlFrame())) {
626 : return true;
627 : }
628 :
629 : // contain: paint, which we should interpret as -moz-hidden-unscrollable
630 : // by default.
631 996 : if (aDisp->IsContainPaint()) {
632 : return true;
633 : }
634 :
635 : // and overflow:hidden that we should interpret as -moz-hidden-unscrollable
636 0 : if (aDisp->mOverflowX == NS_STYLE_OVERFLOW_HIDDEN &&
637 : aDisp->mOverflowY == NS_STYLE_OVERFLOW_HIDDEN) {
638 : // REVIEW: these are the frame types that set up clipping.
639 0 : mozilla::LayoutFrameType type = aFrame->Type();
640 0 : if (type == mozilla::LayoutFrameType::Table ||
641 84 : type == mozilla::LayoutFrameType::TableCell ||
642 84 : type == mozilla::LayoutFrameType::BCTableCell ||
643 0 : type == mozilla::LayoutFrameType::SVGOuterSVG ||
644 0 : type == mozilla::LayoutFrameType::SVGInnerSVG ||
645 168 : type == mozilla::LayoutFrameType::SVGSymbol ||
646 84 : type == mozilla::LayoutFrameType::SVGForeignObject) {
647 : return true;
648 : }
649 84 : if (aFrame->IsFrameOfType(nsIFrame::eReplacedContainsBlock)) {
650 16 : if (type == mozilla::LayoutFrameType::TextInput) {
651 : // It always has an anonymous scroll frame that handles any overflow.
652 : return false;
653 : }
654 16 : return true;
655 : }
656 : }
657 :
658 0 : if ((aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
659 : return false;
660 : }
661 :
662 : // If we're paginated and a block, and have NS_BLOCK_CLIP_PAGINATED_OVERFLOW
663 : // set, then we want to clip our overflow.
664 1857 : return (aFrame->GetStateBits() & NS_BLOCK_CLIP_PAGINATED_OVERFLOW) != 0 &&
665 969 : aFrame->PresContext()->IsPaginated() && aFrame->IsBlockFrame();
666 : }
667 :
668 : nsILineIterator* GetLineIterator() override;
669 :
670 : protected:
671 :
672 : // Test if we are selecting a table object:
673 : // Most table/cell selection requires that Ctrl (Cmd on Mac) key is down
674 : // during a mouse click or drag. Exception is using Shift+click when
675 : // already in "table/cell selection mode" to extend a block selection
676 : // Get the parent content node and offset of the frame
677 : // of the enclosing cell or table (if not inside a cell)
678 : // aTarget tells us what table element to select (currently only cell and table supported)
679 : // (enums for this are defined in nsIFrame.h)
680 : nsresult GetDataForTableSelection(const nsFrameSelection* aFrameSelection,
681 : nsIPresShell* aPresShell,
682 : mozilla::WidgetMouseEvent* aMouseEvent,
683 : nsIContent** aParentContent,
684 : int32_t* aContentOffset,
685 : mozilla::TableSelection* aTarget);
686 :
687 : // Fills aCursor with the appropriate information from ui
688 : static void FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
689 : nsIFrame::Cursor& aCursor);
690 : NS_IMETHOD DoXULLayout(nsBoxLayoutState& aBoxLayoutState) override;
691 :
692 : nsBoxLayoutMetrics* BoxMetrics() const;
693 :
694 : // Fire DOM event. If no aContent argument use frame's mContent.
695 : void FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent = nullptr);
696 :
697 : private:
698 : void BoxReflow(nsBoxLayoutState& aState,
699 : nsPresContext* aPresContext,
700 : ReflowOutput& aDesiredSize,
701 : gfxContext* aRenderingContext,
702 : nscoord aX,
703 : nscoord aY,
704 : nscoord aWidth,
705 : nscoord aHeight,
706 : bool aMoveFrame = true);
707 :
708 : NS_IMETHODIMP RefreshSizeCache(nsBoxLayoutState& aState);
709 :
710 : // Returns true if this frame has any kind of CSS animations.
711 : bool HasCSSAnimations();
712 :
713 : // Returns true if this frame has any kind of CSS transitions.
714 : bool HasCSSTransitions();
715 :
716 : public:
717 :
718 : #ifdef DEBUG_FRAME_DUMP
719 : /**
720 : * Get a printable from of the name of the frame type.
721 : * XXX This should be eliminated and we use GetType() instead...
722 : */
723 : nsresult GetFrameName(nsAString& aResult) const override;
724 : nsresult MakeFrameName(const nsAString& aKind, nsAString& aResult) const;
725 : // Helper function to return the index in parent of the frame's content
726 : // object. Returns -1 on error or if the frame doesn't have a content object
727 : static int32_t ContentIndexInContainer(const nsIFrame* aFrame);
728 : #endif
729 :
730 : #ifdef DEBUG
731 : static mozilla::LazyLogModule sFrameLogModule;
732 :
733 : // Show frame borders when rendering
734 : static void ShowFrameBorders(bool aEnable);
735 : static bool GetShowFrameBorders();
736 :
737 : // Show frame border of event target
738 : static void ShowEventTargetFrameBorder(bool aEnable);
739 : static bool GetShowEventTargetFrameBorder();
740 : #endif
741 :
742 0 : static void PrintDisplayList(nsDisplayListBuilder* aBuilder,
743 : const nsDisplayList& aList,
744 : bool aDumpHtml = false)
745 : {
746 : std::stringstream ss;
747 : PrintDisplayList(aBuilder, aList, ss, aDumpHtml);
748 : fprintf_stderr(stderr, "%s", ss.str().c_str());
749 : }
750 : static void PrintDisplayList(nsDisplayListBuilder* aBuilder,
751 : const nsDisplayList& aList,
752 : std::stringstream& aStream,
753 : bool aDumpHtml = false);
754 : static void PrintDisplayListSet(nsDisplayListBuilder* aBuilder,
755 : const nsDisplayListSet& aList,
756 : std::stringstream& aStream,
757 : bool aDumpHtml = false);
758 :
759 : };
760 :
761 : // Start Display Reflow Debugging
762 : #ifdef DEBUG
763 :
764 : struct DR_cookie {
765 : DR_cookie(nsPresContext* aPresContext,
766 : nsIFrame* aFrame,
767 : const mozilla::ReflowInput& aReflowInput,
768 : mozilla::ReflowOutput& aMetrics,
769 : nsReflowStatus& aStatus);
770 : ~DR_cookie();
771 : void Change() const;
772 :
773 : nsPresContext* mPresContext;
774 : nsIFrame* mFrame;
775 : const mozilla::ReflowInput& mReflowInput;
776 : mozilla::ReflowOutput& mMetrics;
777 : nsReflowStatus& mStatus;
778 : void* mValue;
779 : };
780 :
781 : struct DR_layout_cookie {
782 : explicit DR_layout_cookie(nsIFrame* aFrame);
783 : ~DR_layout_cookie();
784 :
785 : nsIFrame* mFrame;
786 : void* mValue;
787 : };
788 :
789 : struct DR_intrinsic_width_cookie {
790 : DR_intrinsic_width_cookie(nsIFrame* aFrame, const char* aType,
791 : nscoord& aResult);
792 : ~DR_intrinsic_width_cookie();
793 :
794 : nsIFrame* mFrame;
795 : const char* mType;
796 : nscoord& mResult;
797 : void* mValue;
798 : };
799 :
800 : struct DR_intrinsic_size_cookie {
801 : DR_intrinsic_size_cookie(nsIFrame* aFrame, const char* aType,
802 : nsSize& aResult);
803 : ~DR_intrinsic_size_cookie();
804 :
805 : nsIFrame* mFrame;
806 : const char* mType;
807 : nsSize& mResult;
808 : void* mValue;
809 : };
810 :
811 : struct DR_init_constraints_cookie {
812 : DR_init_constraints_cookie(nsIFrame* aFrame, mozilla::ReflowInput* aState,
813 : nscoord aCBWidth, nscoord aCBHeight,
814 : const nsMargin* aBorder,
815 : const nsMargin* aPadding);
816 : ~DR_init_constraints_cookie();
817 :
818 : nsIFrame* mFrame;
819 : mozilla::ReflowInput* mState;
820 : void* mValue;
821 : };
822 :
823 : struct DR_init_offsets_cookie {
824 : DR_init_offsets_cookie(nsIFrame* aFrame, mozilla::SizeComputationInput* aState,
825 : nscoord aPercentBasis,
826 : mozilla::WritingMode aCBWritingMode,
827 : const nsMargin* aBorder,
828 : const nsMargin* aPadding);
829 : ~DR_init_offsets_cookie();
830 :
831 : nsIFrame* mFrame;
832 : mozilla::SizeComputationInput* mState;
833 : void* mValue;
834 : };
835 :
836 : struct DR_init_type_cookie {
837 : DR_init_type_cookie(nsIFrame* aFrame, mozilla::ReflowInput* aState);
838 : ~DR_init_type_cookie();
839 :
840 : nsIFrame* mFrame;
841 : mozilla::ReflowInput* mState;
842 : void* mValue;
843 : };
844 :
845 : #define DISPLAY_REFLOW(dr_pres_context, dr_frame, dr_rf_state, dr_rf_metrics, dr_rf_status) \
846 : DR_cookie dr_cookie(dr_pres_context, dr_frame, dr_rf_state, dr_rf_metrics, dr_rf_status);
847 : #define DISPLAY_REFLOW_CHANGE() \
848 : dr_cookie.Change();
849 : #define DISPLAY_LAYOUT(dr_frame) \
850 : DR_layout_cookie dr_cookie(dr_frame);
851 : #define DISPLAY_MIN_WIDTH(dr_frame, dr_result) \
852 : DR_intrinsic_width_cookie dr_cookie(dr_frame, "Min", dr_result)
853 : #define DISPLAY_PREF_WIDTH(dr_frame, dr_result) \
854 : DR_intrinsic_width_cookie dr_cookie(dr_frame, "Pref", dr_result)
855 : #define DISPLAY_PREF_SIZE(dr_frame, dr_result) \
856 : DR_intrinsic_size_cookie dr_cookie(dr_frame, "Pref", dr_result)
857 : #define DISPLAY_MIN_SIZE(dr_frame, dr_result) \
858 : DR_intrinsic_size_cookie dr_cookie(dr_frame, "Min", dr_result)
859 : #define DISPLAY_MAX_SIZE(dr_frame, dr_result) \
860 : DR_intrinsic_size_cookie dr_cookie(dr_frame, "Max", dr_result)
861 : #define DISPLAY_INIT_CONSTRAINTS(dr_frame, dr_state, dr_cbw, dr_cbh, \
862 : dr_bdr, dr_pad) \
863 : DR_init_constraints_cookie dr_cookie(dr_frame, dr_state, dr_cbw, dr_cbh, \
864 : dr_bdr, dr_pad)
865 : #define DISPLAY_INIT_OFFSETS(dr_frame, dr_state, dr_pb, dr_cbwm, dr_bdr, \
866 : dr_pad) \
867 : DR_init_offsets_cookie dr_cookie(dr_frame, dr_state, dr_pb, dr_cbwm, \
868 : dr_bdr, dr_pad)
869 : #define DISPLAY_INIT_TYPE(dr_frame, dr_result) \
870 : DR_init_type_cookie dr_cookie(dr_frame, dr_result)
871 :
872 : #else
873 :
874 : #define DISPLAY_REFLOW(dr_pres_context, dr_frame, dr_rf_state, dr_rf_metrics, dr_rf_status)
875 : #define DISPLAY_REFLOW_CHANGE()
876 : #define DISPLAY_LAYOUT(dr_frame) PR_BEGIN_MACRO PR_END_MACRO
877 : #define DISPLAY_MIN_WIDTH(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
878 : #define DISPLAY_PREF_WIDTH(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
879 : #define DISPLAY_PREF_SIZE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
880 : #define DISPLAY_MIN_SIZE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
881 : #define DISPLAY_MAX_SIZE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
882 : #define DISPLAY_INIT_CONSTRAINTS(dr_frame, dr_state, dr_cbw, dr_cbh, \
883 : dr_bdr, dr_pad) \
884 : PR_BEGIN_MACRO PR_END_MACRO
885 : #define DISPLAY_INIT_OFFSETS(dr_frame, dr_state, dr_pb, dr_cbwm, dr_bdr, \
886 : dr_pad) \
887 : PR_BEGIN_MACRO PR_END_MACRO
888 : #define DISPLAY_INIT_TYPE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
889 :
890 : #endif
891 : // End Display Reflow Debugging
892 :
893 : // similar to NS_ENSURE_TRUE but with no return value
894 : #define ENSURE_TRUE(x) \
895 : PR_BEGIN_MACRO \
896 : if (!(x)) { \
897 : NS_WARNING("ENSURE_TRUE(" #x ") failed"); \
898 : return; \
899 : } \
900 : PR_END_MACRO
901 : #endif /* nsFrame_h___ */
|