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