|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 sw=2 et tw=78: */ |
|
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 /* interface for all rendering objects */ |
|
8 |
|
9 #ifndef nsIFrame_h___ |
|
10 #define nsIFrame_h___ |
|
11 |
|
12 #ifndef MOZILLA_INTERNAL_API |
|
13 #error This header/class should only be used within Mozilla code. It should not be used by extensions. |
|
14 #endif |
|
15 |
|
16 #define MAX_REFLOW_DEPTH 200 |
|
17 |
|
18 /* nsIFrame is in the process of being deCOMtaminated, i.e., this file is eventually |
|
19 going to be eliminated, and all callers will use nsFrame instead. At the moment |
|
20 we're midway through this process, so you will see inlined functions and member |
|
21 variables in this file. -dwh */ |
|
22 |
|
23 #include <stdio.h> |
|
24 #include "nsQueryFrame.h" |
|
25 #include "nsStyleContext.h" |
|
26 #include "nsStyleStruct.h" |
|
27 #include "nsHTMLReflowMetrics.h" |
|
28 #include "nsFrameList.h" |
|
29 #include "mozilla/layout/FrameChildList.h" |
|
30 #include "FramePropertyTable.h" |
|
31 #include "mozilla/TypedEnum.h" |
|
32 #include "nsDirection.h" |
|
33 #include "WritingModes.h" |
|
34 #include <algorithm> |
|
35 #include "nsITheme.h" |
|
36 #include "gfx3DMatrix.h" |
|
37 #include "nsLayoutUtils.h" |
|
38 #include "nsFrameState.h" |
|
39 |
|
40 #ifdef ACCESSIBILITY |
|
41 #include "mozilla/a11y/AccTypes.h" |
|
42 #endif |
|
43 |
|
44 /** |
|
45 * New rules of reflow: |
|
46 * 1. you get a WillReflow() followed by a Reflow() followed by a DidReflow() in order |
|
47 * (no separate pass over the tree) |
|
48 * 2. it's the parent frame's responsibility to size/position the child's view (not |
|
49 * the child frame's responsibility as it is today) during reflow (and before |
|
50 * sending the DidReflow() notification) |
|
51 * 3. positioning of child frames (and their views) is done on the way down the tree, |
|
52 * and sizing of child frames (and their views) on the way back up |
|
53 * 4. if you move a frame (outside of the reflow process, or after reflowing it), |
|
54 * then you must make sure that its view (or its child frame's views) are re-positioned |
|
55 * as well. It's reasonable to not position the view until after all reflowing the |
|
56 * entire line, for example, but the frame should still be positioned and sized (and |
|
57 * the view sized) during the reflow (i.e., before sending the DidReflow() notification) |
|
58 * 5. the view system handles moving of widgets, i.e., it's not our problem |
|
59 */ |
|
60 |
|
61 struct nsHTMLReflowState; |
|
62 class nsHTMLReflowCommand; |
|
63 |
|
64 struct gfxMatrix; |
|
65 class nsIAtom; |
|
66 class nsPresContext; |
|
67 class nsIPresShell; |
|
68 class nsRenderingContext; |
|
69 class nsView; |
|
70 class nsIWidget; |
|
71 class nsIDOMRange; |
|
72 class nsISelectionController; |
|
73 class nsBoxLayoutState; |
|
74 class nsBoxLayout; |
|
75 class nsILineIterator; |
|
76 class nsDisplayListBuilder; |
|
77 class nsDisplayListSet; |
|
78 class nsDisplayList; |
|
79 class gfxSkipChars; |
|
80 class gfxSkipCharsIterator; |
|
81 class gfxContext; |
|
82 class nsLineList_iterator; |
|
83 class nsAbsoluteContainingBlock; |
|
84 class nsIContent; |
|
85 |
|
86 struct nsPeekOffsetStruct; |
|
87 struct nsPoint; |
|
88 struct nsRect; |
|
89 struct nsSize; |
|
90 struct nsMargin; |
|
91 struct CharacterDataChangeInfo; |
|
92 |
|
93 namespace mozilla { |
|
94 |
|
95 class EventStates; |
|
96 |
|
97 namespace layers { |
|
98 class Layer; |
|
99 } |
|
100 |
|
101 namespace gfx { |
|
102 class Matrix; |
|
103 } |
|
104 } |
|
105 |
|
106 /** |
|
107 * Indication of how the frame can be split. This is used when doing runaround |
|
108 * of floats, and when pulling up child frames from a next-in-flow. |
|
109 * |
|
110 * The choices are splittable, not splittable at all, and splittable in |
|
111 * a non-rectangular fashion. This last type only applies to block-level |
|
112 * elements, and indicates whether splitting can be used when doing runaround. |
|
113 * If you can split across page boundaries, but you expect each continuing |
|
114 * frame to be the same width then return frSplittable and not |
|
115 * frSplittableNonRectangular. |
|
116 * |
|
117 * @see #GetSplittableType() |
|
118 */ |
|
119 typedef uint32_t nsSplittableType; |
|
120 |
|
121 #define NS_FRAME_NOT_SPLITTABLE 0 // Note: not a bit! |
|
122 #define NS_FRAME_SPLITTABLE 0x1 |
|
123 #define NS_FRAME_SPLITTABLE_NON_RECTANGULAR 0x3 |
|
124 |
|
125 #define NS_FRAME_IS_SPLITTABLE(type)\ |
|
126 (0 != ((type) & NS_FRAME_SPLITTABLE)) |
|
127 |
|
128 #define NS_FRAME_IS_NOT_SPLITTABLE(type)\ |
|
129 (0 == ((type) & NS_FRAME_SPLITTABLE)) |
|
130 |
|
131 #define NS_INTRINSIC_WIDTH_UNKNOWN nscoord_MIN |
|
132 |
|
133 //---------------------------------------------------------------------- |
|
134 |
|
135 #define NS_SUBTREE_DIRTY(_frame) \ |
|
136 (((_frame)->GetStateBits() & \ |
|
137 (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0) |
|
138 |
|
139 /** |
|
140 * Constant used to indicate an unconstrained size. |
|
141 * |
|
142 * @see #Reflow() |
|
143 */ |
|
144 #define NS_UNCONSTRAINEDSIZE NS_MAXSIZE |
|
145 |
|
146 #define NS_INTRINSICSIZE NS_UNCONSTRAINEDSIZE |
|
147 #define NS_AUTOHEIGHT NS_UNCONSTRAINEDSIZE |
|
148 #define NS_AUTOMARGIN NS_UNCONSTRAINEDSIZE |
|
149 #define NS_AUTOOFFSET NS_UNCONSTRAINEDSIZE |
|
150 // NOTE: there are assumptions all over that these have the same value, namely NS_UNCONSTRAINEDSIZE |
|
151 // if any are changed to be a value other than NS_UNCONSTRAINEDSIZE |
|
152 // at least update AdjustComputedHeight/Width and test ad nauseum |
|
153 |
|
154 //---------------------------------------------------------------------- |
|
155 |
|
156 enum nsSelectionAmount { |
|
157 eSelectCharacter = 0, // a single Unicode character; |
|
158 // do not use this (prefer Cluster) unless you |
|
159 // are really sure it's what you want |
|
160 eSelectCluster = 1, // a grapheme cluster: this is usually the right |
|
161 // choice for movement or selection by "character" |
|
162 // as perceived by the user |
|
163 eSelectWord = 2, |
|
164 eSelectLine = 3, // previous drawn line in flow. |
|
165 eSelectBeginLine = 4, |
|
166 eSelectEndLine = 5, |
|
167 eSelectNoAmount = 6, // just bounce back current offset. |
|
168 eSelectParagraph = 7, // select a "paragraph" |
|
169 eSelectWordNoSpace = 8 // select a "word" without selecting the following |
|
170 // space, no matter what the default platform |
|
171 // behavior is |
|
172 }; |
|
173 |
|
174 enum nsSpread { |
|
175 eSpreadNone = 0, |
|
176 eSpreadAcross = 1, |
|
177 eSpreadDown = 2 |
|
178 }; |
|
179 |
|
180 // Carried out margin flags |
|
181 #define NS_CARRIED_TOP_MARGIN_IS_AUTO 0x1 |
|
182 #define NS_CARRIED_BOTTOM_MARGIN_IS_AUTO 0x2 |
|
183 |
|
184 //---------------------------------------------------------------------- |
|
185 |
|
186 /** |
|
187 * Reflow status returned by the reflow methods. There are three |
|
188 * completion statuses, represented by two bit flags. |
|
189 * |
|
190 * NS_FRAME_COMPLETE means the frame is fully complete. |
|
191 * |
|
192 * NS_FRAME_NOT_COMPLETE bit flag means the frame does not map all its |
|
193 * content, and that the parent frame should create a continuing frame. |
|
194 * If this bit isn't set it means the frame does map all its content. |
|
195 * This bit is mutually exclusive with NS_FRAME_OVERFLOW_INCOMPLETE. |
|
196 * |
|
197 * NS_FRAME_OVERFLOW_INCOMPLETE bit flag means that the frame has |
|
198 * overflow that is not complete, but its own box is complete. |
|
199 * (This happens when content overflows a fixed-height box.) |
|
200 * The reflower should place and size the frame and continue its reflow, |
|
201 * but needs to create an overflow container as a continuation for this |
|
202 * frame. See nsContainerFrame.h for more information. |
|
203 * This bit is mutually exclusive with NS_FRAME_NOT_COMPLETE. |
|
204 * |
|
205 * Please use the SET macro for handling |
|
206 * NS_FRAME_NOT_COMPLETE and NS_FRAME_OVERFLOW_INCOMPLETE. |
|
207 * |
|
208 * NS_FRAME_REFLOW_NEXTINFLOW bit flag means that the next-in-flow is |
|
209 * dirty, and also needs to be reflowed. This status only makes sense |
|
210 * for a frame that is not complete, i.e. you wouldn't set both |
|
211 * NS_FRAME_COMPLETE and NS_FRAME_REFLOW_NEXTINFLOW. |
|
212 * |
|
213 * The low 8 bits of the nsReflowStatus are reserved for future extensions; |
|
214 * the remaining 24 bits are zero (and available for extensions; however |
|
215 * API's that accept/return nsReflowStatus must not receive/return any |
|
216 * extension bits). |
|
217 * |
|
218 * @see #Reflow() |
|
219 */ |
|
220 typedef uint32_t nsReflowStatus; |
|
221 |
|
222 #define NS_FRAME_COMPLETE 0 // Note: not a bit! |
|
223 #define NS_FRAME_NOT_COMPLETE 0x1 |
|
224 #define NS_FRAME_REFLOW_NEXTINFLOW 0x2 |
|
225 #define NS_FRAME_OVERFLOW_INCOMPLETE 0x4 |
|
226 |
|
227 #define NS_FRAME_IS_COMPLETE(status) \ |
|
228 (0 == ((status) & NS_FRAME_NOT_COMPLETE)) |
|
229 |
|
230 #define NS_FRAME_IS_NOT_COMPLETE(status) \ |
|
231 (0 != ((status) & NS_FRAME_NOT_COMPLETE)) |
|
232 |
|
233 #define NS_FRAME_OVERFLOW_IS_INCOMPLETE(status) \ |
|
234 (0 != ((status) & NS_FRAME_OVERFLOW_INCOMPLETE)) |
|
235 |
|
236 #define NS_FRAME_IS_FULLY_COMPLETE(status) \ |
|
237 (NS_FRAME_IS_COMPLETE(status) && !NS_FRAME_OVERFLOW_IS_INCOMPLETE(status)) |
|
238 |
|
239 // These macros set or switch incomplete statuses without touching the |
|
240 // NS_FRAME_REFLOW_NEXTINFLOW bit. |
|
241 #define NS_FRAME_SET_INCOMPLETE(status) \ |
|
242 status = (status & ~NS_FRAME_OVERFLOW_INCOMPLETE) | NS_FRAME_NOT_COMPLETE |
|
243 |
|
244 #define NS_FRAME_SET_OVERFLOW_INCOMPLETE(status) \ |
|
245 status = (status & ~NS_FRAME_NOT_COMPLETE) | NS_FRAME_OVERFLOW_INCOMPLETE |
|
246 |
|
247 // This macro tests to see if an nsReflowStatus is an error value |
|
248 // or just a regular return value |
|
249 #define NS_IS_REFLOW_ERROR(_status) (int32_t(_status) < 0) |
|
250 |
|
251 /** |
|
252 * Extensions to the reflow status bits defined by nsIFrameReflow |
|
253 */ |
|
254 |
|
255 // This bit is set, when a break is requested. This bit is orthogonal |
|
256 // to the nsIFrame::nsReflowStatus completion bits. |
|
257 #define NS_INLINE_BREAK 0x0100 |
|
258 |
|
259 // When a break is requested, this bit when set indicates that the |
|
260 // break should occur after the frame just reflowed; when the bit is |
|
261 // clear the break should occur before the frame just reflowed. |
|
262 #define NS_INLINE_BREAK_BEFORE 0x0000 |
|
263 #define NS_INLINE_BREAK_AFTER 0x0200 |
|
264 |
|
265 // The type of break requested can be found in these bits. |
|
266 #define NS_INLINE_BREAK_TYPE_MASK 0xF000 |
|
267 |
|
268 // Set when a break was induced by completion of a first-letter |
|
269 #define NS_INLINE_BREAK_FIRST_LETTER_COMPLETE 0x10000 |
|
270 |
|
271 //---------------------------------------- |
|
272 // Macros that use those bits |
|
273 |
|
274 #define NS_INLINE_IS_BREAK(_status) \ |
|
275 (0 != ((_status) & NS_INLINE_BREAK)) |
|
276 |
|
277 #define NS_INLINE_IS_BREAK_AFTER(_status) \ |
|
278 (0 != ((_status) & NS_INLINE_BREAK_AFTER)) |
|
279 |
|
280 #define NS_INLINE_IS_BREAK_BEFORE(_status) \ |
|
281 (NS_INLINE_BREAK == ((_status) & (NS_INLINE_BREAK|NS_INLINE_BREAK_AFTER))) |
|
282 |
|
283 #define NS_INLINE_GET_BREAK_TYPE(_status) (((_status) >> 12) & 0xF) |
|
284 |
|
285 #define NS_INLINE_MAKE_BREAK_TYPE(_type) ((_type) << 12) |
|
286 |
|
287 // Construct a line-break-before status. Note that there is no |
|
288 // completion status for a line-break before because we *know* that |
|
289 // the frame will be reflowed later and hence its current completion |
|
290 // status doesn't matter. |
|
291 #define NS_INLINE_LINE_BREAK_BEFORE() \ |
|
292 (NS_INLINE_BREAK | NS_INLINE_BREAK_BEFORE | \ |
|
293 NS_INLINE_MAKE_BREAK_TYPE(NS_STYLE_CLEAR_LINE)) |
|
294 |
|
295 // Take a completion status and add to it the desire to have a |
|
296 // line-break after. For this macro we do need the completion status |
|
297 // because the user of the status will need to know whether to |
|
298 // continue the frame or not. |
|
299 #define NS_INLINE_LINE_BREAK_AFTER(_completionStatus) \ |
|
300 ((_completionStatus) | NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER | \ |
|
301 NS_INLINE_MAKE_BREAK_TYPE(NS_STYLE_CLEAR_LINE)) |
|
302 |
|
303 // A frame is "truncated" if the part of the frame before the first |
|
304 // possible break point was unable to fit in the available vertical |
|
305 // space. Therefore, the entire frame should be moved to the next page. |
|
306 // A frame that begins at the top of the page must never be "truncated". |
|
307 // Doing so would likely cause an infinite loop. |
|
308 #define NS_FRAME_TRUNCATED 0x0010 |
|
309 #define NS_FRAME_IS_TRUNCATED(status) \ |
|
310 (0 != ((status) & NS_FRAME_TRUNCATED)) |
|
311 #define NS_FRAME_SET_TRUNCATION(status, aReflowState, aMetrics) \ |
|
312 aReflowState.SetTruncated(aMetrics, &status); |
|
313 |
|
314 // Merge the incompleteness, truncation and NS_FRAME_REFLOW_NEXTINFLOW |
|
315 // status from aSecondary into aPrimary. |
|
316 void NS_MergeReflowStatusInto(nsReflowStatus* aPrimary, |
|
317 nsReflowStatus aSecondary); |
|
318 |
|
319 //---------------------------------------------------------------------- |
|
320 |
|
321 /** |
|
322 * DidReflow status values. |
|
323 */ |
|
324 MOZ_BEGIN_ENUM_CLASS(nsDidReflowStatus, uint32_t) |
|
325 NOT_FINISHED, |
|
326 FINISHED |
|
327 MOZ_END_ENUM_CLASS(nsDidReflowStatus) |
|
328 |
|
329 /** |
|
330 * When there is no scrollable overflow rect, the visual overflow rect |
|
331 * may be stored as four 1-byte deltas each strictly LESS THAN 0xff, for |
|
332 * the four edges of the rectangle, or the four bytes may be read as a |
|
333 * single 32-bit "overflow-rect type" value including at least one 0xff |
|
334 * byte as an indicator that the value does NOT represent four deltas. |
|
335 * If all four deltas are zero, this means that no overflow rect has |
|
336 * actually been set (this is the initial state of newly-created frames). |
|
337 */ |
|
338 #define NS_FRAME_OVERFLOW_DELTA_MAX 0xfe // max delta we can store |
|
339 |
|
340 #define NS_FRAME_OVERFLOW_NONE 0x00000000 // there are no overflow rects; |
|
341 // code relies on this being |
|
342 // the all-zero value |
|
343 |
|
344 #define NS_FRAME_OVERFLOW_LARGE 0x000000ff // overflow is stored as a |
|
345 // separate rect property |
|
346 |
|
347 namespace mozilla { |
|
348 /* |
|
349 * For replaced elements only. Gets the intrinsic dimensions of this element. |
|
350 * The dimensions may only be one of the following two types: |
|
351 * |
|
352 * eStyleUnit_Coord - a length in app units |
|
353 * eStyleUnit_None - the element has no intrinsic size in this dimension |
|
354 */ |
|
355 struct IntrinsicSize { |
|
356 nsStyleCoord width, height; |
|
357 |
|
358 IntrinsicSize() |
|
359 : width(eStyleUnit_None), height(eStyleUnit_None) |
|
360 {} |
|
361 IntrinsicSize(const IntrinsicSize& rhs) |
|
362 : width(rhs.width), height(rhs.height) |
|
363 {} |
|
364 IntrinsicSize& operator=(const IntrinsicSize& rhs) { |
|
365 width = rhs.width; height = rhs.height; return *this; |
|
366 } |
|
367 bool operator==(const IntrinsicSize& rhs) { |
|
368 return width == rhs.width && height == rhs.height; |
|
369 } |
|
370 bool operator!=(const IntrinsicSize& rhs) { |
|
371 return !(*this == rhs); |
|
372 } |
|
373 }; |
|
374 } |
|
375 |
|
376 //---------------------------------------------------------------------- |
|
377 |
|
378 /** |
|
379 * A frame in the layout model. This interface is supported by all frame |
|
380 * objects. |
|
381 * |
|
382 * Frames can have multiple child lists: the default child list |
|
383 * (referred to as the <i>principal</i> child list, and additional named |
|
384 * child lists. There is an ordering of frames within a child list, but |
|
385 * there is no order defined between frames in different child lists of |
|
386 * the same parent frame. |
|
387 * |
|
388 * Frames are NOT reference counted. Use the Destroy() member function |
|
389 * to destroy a frame. The lifetime of the frame hierarchy is bounded by the |
|
390 * lifetime of the presentation shell which owns the frames. |
|
391 * |
|
392 * nsIFrame is a private Gecko interface. If you are not Gecko then you |
|
393 * should not use it. If you're not in layout, then you won't be able to |
|
394 * link to many of the functions defined here. Too bad. |
|
395 * |
|
396 * If you're not in layout but you must call functions in here, at least |
|
397 * restrict yourself to calling virtual methods, which won't hurt you as badly. |
|
398 */ |
|
399 class nsIFrame : public nsQueryFrame |
|
400 { |
|
401 public: |
|
402 typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor; |
|
403 typedef mozilla::FrameProperties FrameProperties; |
|
404 typedef mozilla::layers::Layer Layer; |
|
405 typedef mozilla::layout::FrameChildList ChildList; |
|
406 typedef mozilla::layout::FrameChildListID ChildListID; |
|
407 typedef mozilla::layout::FrameChildListIDs ChildListIDs; |
|
408 typedef mozilla::layout::FrameChildListIterator ChildListIterator; |
|
409 typedef mozilla::layout::FrameChildListArrayIterator ChildListArrayIterator; |
|
410 typedef mozilla::gfx::Matrix Matrix; |
|
411 |
|
412 NS_DECL_QUERYFRAME_TARGET(nsIFrame) |
|
413 |
|
414 nsPresContext* PresContext() const { |
|
415 return StyleContext()->RuleNode()->PresContext(); |
|
416 } |
|
417 |
|
418 /** |
|
419 * Called to initialize the frame. This is called immediately after creating |
|
420 * the frame. |
|
421 * |
|
422 * If the frame is a continuing frame, then aPrevInFlow indicates the previous |
|
423 * frame (the frame that was split). |
|
424 * |
|
425 * If you want a view associated with your frame, you should create the view |
|
426 * after Init() has returned. |
|
427 * |
|
428 * @param aContent the content object associated with the frame |
|
429 * @param aParent the parent frame |
|
430 * @param aPrevInFlow the prev-in-flow frame |
|
431 */ |
|
432 virtual void Init(nsIContent* aContent, |
|
433 nsIFrame* aParent, |
|
434 nsIFrame* aPrevInFlow) = 0; |
|
435 |
|
436 /** |
|
437 * Destroys this frame and each of its child frames (recursively calls |
|
438 * Destroy() for each child). If this frame is a first-continuation, this |
|
439 * also removes the frame from the primary frame map and clears undisplayed |
|
440 * content for its content node. |
|
441 * If the frame is a placeholder, it also ensures the out-of-flow frame's |
|
442 * removal and destruction. |
|
443 */ |
|
444 void Destroy() { DestroyFrom(this); } |
|
445 |
|
446 /** Flags for PeekOffsetCharacter, PeekOffsetNoAmount, PeekOffsetWord return values. |
|
447 */ |
|
448 enum FrameSearchResult { |
|
449 // Peek found a appropriate offset within frame. |
|
450 FOUND = 0x00, |
|
451 // try next frame for offset. |
|
452 CONTINUE = 0x1, |
|
453 // offset not found because the frame was empty of text. |
|
454 CONTINUE_EMPTY = 0x2 | CONTINUE, |
|
455 // offset not found because the frame didn't contain any text that could be selected. |
|
456 CONTINUE_UNSELECTABLE = 0x4 | CONTINUE, |
|
457 }; |
|
458 |
|
459 protected: |
|
460 /** |
|
461 * Return true if the frame is part of a Selection. |
|
462 * Helper method to implement the public IsSelected() API. |
|
463 */ |
|
464 virtual bool IsFrameSelected() const; |
|
465 |
|
466 /** |
|
467 * Implements Destroy(). Do not call this directly except from within a |
|
468 * DestroyFrom() implementation. |
|
469 * |
|
470 * @note This will always be called, so it is not necessary to override |
|
471 * Destroy() in subclasses of nsFrame, just DestroyFrom(). |
|
472 * |
|
473 * @param aDestructRoot is the root of the subtree being destroyed |
|
474 */ |
|
475 virtual void DestroyFrom(nsIFrame* aDestructRoot) = 0; |
|
476 friend class nsFrameList; // needed to pass aDestructRoot through to children |
|
477 friend class nsLineBox; // needed to pass aDestructRoot through to children |
|
478 friend class nsContainerFrame; // needed to pass aDestructRoot through to children |
|
479 public: |
|
480 |
|
481 /** |
|
482 * Called to set the initial list of frames. This happens after the frame |
|
483 * has been initialized. |
|
484 * |
|
485 * This is only called once for a given child list, and won't be called |
|
486 * at all for child lists with no initial list of frames. |
|
487 * |
|
488 * @param aListID the child list identifier. |
|
489 * @param aChildList list of child frames. Each of the frames has its |
|
490 * NS_FRAME_IS_DIRTY bit set. Must not be empty. |
|
491 * This method cannot handle the child list returned by |
|
492 * GetAbsoluteListID(). |
|
493 * @return NS_ERROR_INVALID_ARG if there is no child list with the specified |
|
494 * name, |
|
495 * NS_ERROR_UNEXPECTED if the frame is an atomic frame or if the |
|
496 * initial list of frames has already been set for that child list, |
|
497 * NS_OK otherwise. In this case, SetInitialChildList empties out |
|
498 * aChildList in the process of moving the frames over to its own |
|
499 * child list. |
|
500 * @see #Init() |
|
501 */ |
|
502 virtual nsresult SetInitialChildList(ChildListID aListID, |
|
503 nsFrameList& aChildList) = 0; |
|
504 |
|
505 /** |
|
506 * This method is responsible for appending frames to the frame |
|
507 * list. The implementation should append the frames to the specified |
|
508 * child list and then generate a reflow command. |
|
509 * |
|
510 * @param aListID the child list identifier. |
|
511 * @param aFrameList list of child frames to append. Each of the frames has |
|
512 * its NS_FRAME_IS_DIRTY bit set. Must not be empty. |
|
513 * @return NS_ERROR_INVALID_ARG if there is no child list with the specified |
|
514 * name, |
|
515 * NS_ERROR_UNEXPECTED if the frame is an atomic frame, |
|
516 * NS_OK otherwise. In this case, AppendFrames empties out |
|
517 * aFrameList in the process of moving the frames over to its own |
|
518 * child list. |
|
519 */ |
|
520 virtual nsresult AppendFrames(ChildListID aListID, |
|
521 nsFrameList& aFrameList) = 0; |
|
522 |
|
523 /** |
|
524 * This method is responsible for inserting frames into the frame |
|
525 * list. The implementation should insert the new frames into the specified |
|
526 * child list and then generate a reflow command. |
|
527 * |
|
528 * @param aListID the child list identifier. |
|
529 * @param aPrevFrame the frame to insert frames <b>after</b> |
|
530 * @param aFrameList list of child frames to insert <b>after</b> aPrevFrame. |
|
531 * Each of the frames has its NS_FRAME_IS_DIRTY bit set |
|
532 * @return NS_ERROR_INVALID_ARG if there is no child list with the specified |
|
533 * name, |
|
534 * NS_ERROR_UNEXPECTED if the frame is an atomic frame, |
|
535 * NS_OK otherwise. In this case, InsertFrames empties out |
|
536 * aFrameList in the process of moving the frames over to its own |
|
537 * child list. |
|
538 */ |
|
539 virtual nsresult InsertFrames(ChildListID aListID, |
|
540 nsIFrame* aPrevFrame, |
|
541 nsFrameList& aFrameList) = 0; |
|
542 |
|
543 /** |
|
544 * This method is responsible for removing a frame in the frame |
|
545 * list. The implementation should do something with the removed frame |
|
546 * and then generate a reflow command. The implementation is responsible |
|
547 * for destroying aOldFrame (the caller mustn't destroy aOldFrame). |
|
548 * |
|
549 * @param aListID the child list identifier. |
|
550 * @param aOldFrame the frame to remove |
|
551 * @return NS_ERROR_INVALID_ARG if there is no child list with the specified |
|
552 * name, |
|
553 * NS_ERROR_FAILURE if the child frame is not in the specified |
|
554 * child list, |
|
555 * NS_ERROR_UNEXPECTED if the frame is an atomic frame, |
|
556 * NS_OK otherwise |
|
557 */ |
|
558 virtual nsresult RemoveFrame(ChildListID aListID, |
|
559 nsIFrame* aOldFrame) = 0; |
|
560 |
|
561 /** |
|
562 * Get the content object associated with this frame. Does not add a reference. |
|
563 */ |
|
564 nsIContent* GetContent() const { return mContent; } |
|
565 |
|
566 /** |
|
567 * Get the frame that should be the parent for the frames of child elements |
|
568 * May return nullptr during reflow |
|
569 */ |
|
570 virtual nsIFrame* GetContentInsertionFrame() { return this; } |
|
571 |
|
572 /** |
|
573 * Move any frames on our overflow list to the end of our principal list. |
|
574 * @return true if there were any overflow frames |
|
575 */ |
|
576 virtual bool DrainSelfOverflowList() { return false; } |
|
577 |
|
578 /** |
|
579 * Get the frame that should be scrolled if the content associated |
|
580 * with this frame is targeted for scrolling. For frames implementing |
|
581 * nsIScrollableFrame this will return the frame itself. For frames |
|
582 * like nsTextControlFrame that contain a scrollframe, will return |
|
583 * that scrollframe. |
|
584 */ |
|
585 virtual nsIScrollableFrame* GetScrollTargetFrame() { return nullptr; } |
|
586 |
|
587 /** |
|
588 * Get the offsets of the frame. most will be 0,0 |
|
589 * |
|
590 */ |
|
591 virtual nsresult GetOffsets(int32_t &start, int32_t &end) const = 0; |
|
592 |
|
593 /** |
|
594 * Reset the offsets when splitting frames during Bidi reordering |
|
595 * |
|
596 */ |
|
597 virtual void AdjustOffsetsForBidi(int32_t aStart, int32_t aEnd) {} |
|
598 |
|
599 /** |
|
600 * Get the style context associated with this frame. |
|
601 */ |
|
602 nsStyleContext* StyleContext() const { return mStyleContext; } |
|
603 void SetStyleContext(nsStyleContext* aContext) |
|
604 { |
|
605 if (aContext != mStyleContext) { |
|
606 nsStyleContext* oldStyleContext = mStyleContext; |
|
607 mStyleContext = aContext; |
|
608 aContext->AddRef(); |
|
609 DidSetStyleContext(oldStyleContext); |
|
610 oldStyleContext->Release(); |
|
611 } |
|
612 } |
|
613 |
|
614 /** |
|
615 * SetStyleContextWithoutNotification is for changes to the style |
|
616 * context that should suppress style change processing, in other |
|
617 * words, those that aren't really changes. This generally means only |
|
618 * changes that happen during frame construction. |
|
619 */ |
|
620 void SetStyleContextWithoutNotification(nsStyleContext* aContext) |
|
621 { |
|
622 if (aContext != mStyleContext) { |
|
623 mStyleContext->Release(); |
|
624 mStyleContext = aContext; |
|
625 aContext->AddRef(); |
|
626 } |
|
627 } |
|
628 |
|
629 // Style post processing hook |
|
630 // Attention: the old style context is the one we're forgetting, |
|
631 // and hence possibly completely bogus for GetStyle* purposes. |
|
632 // Use PeekStyleData instead. |
|
633 virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) = 0; |
|
634 |
|
635 /** |
|
636 * Define typesafe getter functions for each style struct by |
|
637 * preprocessing the list of style structs. These functions are the |
|
638 * preferred way to get style data. The macro creates functions like: |
|
639 * const nsStyleBorder* StyleBorder(); |
|
640 * const nsStyleColor* StyleColor(); |
|
641 * |
|
642 * Callers outside of libxul should use nsIDOMWindow::GetComputedStyle() |
|
643 * instead of these accessors. |
|
644 */ |
|
645 #define STYLE_STRUCT(name_, checkdata_cb_) \ |
|
646 const nsStyle##name_ * Style##name_ () const { \ |
|
647 NS_ASSERTION(mStyleContext, "No style context found!"); \ |
|
648 return mStyleContext->Style##name_ (); \ |
|
649 } |
|
650 #include "nsStyleStructList.h" |
|
651 #undef STYLE_STRUCT |
|
652 |
|
653 /** Also forward GetVisitedDependentColor to the style context */ |
|
654 nscolor GetVisitedDependentColor(nsCSSProperty aProperty) |
|
655 { return mStyleContext->GetVisitedDependentColor(aProperty); } |
|
656 |
|
657 /** |
|
658 * These methods are to access any additional style contexts that |
|
659 * the frame may be holding. These are contexts that are children |
|
660 * of the frame's primary context and are NOT used as style contexts |
|
661 * for any child frames. These contexts also MUST NOT have any child |
|
662 * contexts whatsoever. If you need to insert style contexts into the |
|
663 * style tree, then you should create pseudo element frames to own them |
|
664 * The indicies must be consecutive and implementations MUST return an |
|
665 * NS_ERROR_INVALID_ARG if asked for an index that is out of range. |
|
666 */ |
|
667 virtual nsStyleContext* GetAdditionalStyleContext(int32_t aIndex) const = 0; |
|
668 |
|
669 virtual void SetAdditionalStyleContext(int32_t aIndex, |
|
670 nsStyleContext* aStyleContext) = 0; |
|
671 |
|
672 /** |
|
673 * Accessor functions for geometric parent |
|
674 */ |
|
675 nsIFrame* GetParent() const { return mParent; } |
|
676 /** |
|
677 * Set this frame's parent to aParent. |
|
678 * If the frame may have moved into or out of a scrollframe's |
|
679 * frame subtree, StickyScrollContainer::NotifyReparentedFrameAcrossScrollFrameBoundary |
|
680 * must also be called. |
|
681 */ |
|
682 virtual void SetParent(nsIFrame* aParent) = 0; |
|
683 |
|
684 /** |
|
685 * The frame's writing-mode, used for logical layout computations. |
|
686 */ |
|
687 mozilla::WritingMode GetWritingMode() const { |
|
688 return mozilla::WritingMode(StyleVisibility()); |
|
689 } |
|
690 |
|
691 /** |
|
692 * Get the writing mode of this frame, but if it is styled with |
|
693 * unicode-bidi: plaintext, reset the direction to the resolved paragraph |
|
694 * level of the given subframe (typically the first frame on the line), |
|
695 * not this frame's writing mode, because the container frame could be split |
|
696 * by hard line breaks into multiple paragraphs with different base direction. |
|
697 */ |
|
698 mozilla::WritingMode GetWritingMode(nsIFrame* aSubFrame) const; |
|
699 |
|
700 /** |
|
701 * Bounding rect of the frame. The values are in app units, and the origin is |
|
702 * relative to the upper-left of the geometric parent. The size includes the |
|
703 * content area, borders, and padding. |
|
704 * |
|
705 * Note: moving or sizing the frame does not affect the view's size or |
|
706 * position. |
|
707 */ |
|
708 nsRect GetRect() const { return mRect; } |
|
709 nsPoint GetPosition() const { return mRect.TopLeft(); } |
|
710 nsSize GetSize() const { return mRect.Size(); } |
|
711 nsRect GetRectRelativeToSelf() const { |
|
712 return nsRect(nsPoint(0, 0), mRect.Size()); |
|
713 } |
|
714 /** |
|
715 * Dimensions and position in logical coordinates in the frame's writing mode |
|
716 * or another writing mode |
|
717 */ |
|
718 mozilla::LogicalRect GetLogicalRect(nscoord aContainerWidth) const { |
|
719 return GetLogicalRect(GetWritingMode(), aContainerWidth); |
|
720 } |
|
721 mozilla::LogicalPoint GetLogicalPosition(nscoord aContainerWidth) const { |
|
722 return GetLogicalPosition(GetWritingMode(), aContainerWidth); |
|
723 } |
|
724 mozilla::LogicalSize GetLogicalSize() const { |
|
725 return GetLogicalSize(GetWritingMode()); |
|
726 } |
|
727 mozilla::LogicalRect GetLogicalRect(mozilla::WritingMode aWritingMode, |
|
728 nscoord aContainerWidth) const { |
|
729 return mozilla::LogicalRect(aWritingMode, GetRect(), aContainerWidth); |
|
730 } |
|
731 mozilla::LogicalPoint GetLogicalPosition(mozilla::WritingMode aWritingMode, |
|
732 nscoord aContainerWidth) const { |
|
733 return GetLogicalRect(aWritingMode, aContainerWidth).Origin(aWritingMode); |
|
734 } |
|
735 mozilla::LogicalSize GetLogicalSize(mozilla::WritingMode aWritingMode) const { |
|
736 return mozilla::LogicalSize(aWritingMode, GetSize()); |
|
737 } |
|
738 nscoord IStart(nscoord aContainerWidth) const { |
|
739 return IStart(GetWritingMode(), aContainerWidth); |
|
740 } |
|
741 nscoord IStart(mozilla::WritingMode aWritingMode, |
|
742 nscoord aContainerWidth) const { |
|
743 return GetLogicalPosition(aWritingMode, aContainerWidth).I(aWritingMode); |
|
744 } |
|
745 nscoord BStart(nscoord aContainerWidth) const { |
|
746 return BStart(GetWritingMode(), aContainerWidth); |
|
747 } |
|
748 nscoord BStart(mozilla::WritingMode aWritingMode, |
|
749 nscoord aContainerWidth) const { |
|
750 return GetLogicalPosition(aWritingMode, aContainerWidth).B(aWritingMode); |
|
751 } |
|
752 nscoord ISize() const { return ISize(GetWritingMode()); } |
|
753 nscoord ISize(mozilla::WritingMode aWritingMode) const { |
|
754 return GetLogicalSize(aWritingMode).ISize(aWritingMode); |
|
755 } |
|
756 nscoord BSize() const { return BSize(GetWritingMode()); } |
|
757 nscoord BSize(mozilla::WritingMode aWritingMode) const { |
|
758 return GetLogicalSize(aWritingMode).BSize(aWritingMode); |
|
759 } |
|
760 |
|
761 /** |
|
762 * When we change the size of the frame's border-box rect, we may need to |
|
763 * reset the overflow rect if it was previously stored as deltas. |
|
764 * (If it is currently a "large" overflow and could be re-packed as deltas, |
|
765 * we don't bother as the cost of the allocation has already been paid.) |
|
766 */ |
|
767 void SetRect(const nsRect& aRect) { |
|
768 if (mOverflow.mType != NS_FRAME_OVERFLOW_LARGE && |
|
769 mOverflow.mType != NS_FRAME_OVERFLOW_NONE) { |
|
770 nsOverflowAreas overflow = GetOverflowAreas(); |
|
771 mRect = aRect; |
|
772 SetOverflowAreas(overflow); |
|
773 } else { |
|
774 mRect = aRect; |
|
775 } |
|
776 } |
|
777 /** |
|
778 * Set this frame's rect from a logical rect in its own writing direction |
|
779 */ |
|
780 void SetRect(const mozilla::LogicalRect& aRect, nscoord aContainerWidth) { |
|
781 SetRect(GetWritingMode(), aRect, aContainerWidth); |
|
782 } |
|
783 /** |
|
784 * Set this frame's rect from a logical rect in a different writing direction |
|
785 * (GetPhysicalRect will assert if the writing mode doesn't match) |
|
786 */ |
|
787 void SetRect(mozilla::WritingMode aWritingMode, |
|
788 const mozilla::LogicalRect& aRect, |
|
789 nscoord aContainerWidth) { |
|
790 SetRect(aRect.GetPhysicalRect(aWritingMode, aContainerWidth)); |
|
791 } |
|
792 void SetSize(const nsSize& aSize) { |
|
793 SetRect(nsRect(mRect.TopLeft(), aSize)); |
|
794 } |
|
795 void SetPosition(const nsPoint& aPt) { mRect.MoveTo(aPt); } |
|
796 |
|
797 /** |
|
798 * Move the frame, accounting for relative positioning. Use this when |
|
799 * adjusting the frame's position by a known amount, to properly update its |
|
800 * saved normal position (see GetNormalPosition below). |
|
801 * |
|
802 * This must be used only when moving a frame *after* |
|
803 * nsHTMLReflowState::ApplyRelativePositioning is called. When moving |
|
804 * a frame during the reflow process prior to calling |
|
805 * nsHTMLReflowState::ApplyRelativePositioning, the position should |
|
806 * simply be adjusted directly (e.g., using SetPosition()). |
|
807 */ |
|
808 void MovePositionBy(const nsPoint& aTranslation); |
|
809 |
|
810 /** |
|
811 * Return frame's position without relative positioning |
|
812 */ |
|
813 nsPoint GetNormalPosition() const; |
|
814 mozilla::LogicalPoint |
|
815 GetLogicalNormalPosition(mozilla::WritingMode aWritingMode, |
|
816 nscoord aContainerWidth) const |
|
817 { |
|
818 return mozilla::LogicalPoint(aWritingMode, |
|
819 GetNormalPosition(), aContainerWidth); |
|
820 } |
|
821 |
|
822 virtual nsPoint GetPositionOfChildIgnoringScrolling(nsIFrame* aChild) |
|
823 { return aChild->GetPosition(); } |
|
824 |
|
825 nsPoint GetPositionIgnoringScrolling() { |
|
826 return mParent ? mParent->GetPositionOfChildIgnoringScrolling(this) |
|
827 : GetPosition(); |
|
828 } |
|
829 |
|
830 static void DestroyRegion(void* aPropertyValue); |
|
831 |
|
832 static void DestroyMargin(void* aPropertyValue) |
|
833 { |
|
834 delete static_cast<nsMargin*>(aPropertyValue); |
|
835 } |
|
836 |
|
837 static void DestroyRect(void* aPropertyValue) |
|
838 { |
|
839 delete static_cast<nsRect*>(aPropertyValue); |
|
840 } |
|
841 |
|
842 static void DestroyPoint(void* aPropertyValue) |
|
843 { |
|
844 delete static_cast<nsPoint*>(aPropertyValue); |
|
845 } |
|
846 |
|
847 static void DestroyOverflowAreas(void* aPropertyValue) |
|
848 { |
|
849 delete static_cast<nsOverflowAreas*>(aPropertyValue); |
|
850 } |
|
851 |
|
852 static void DestroySurface(void* aPropertyValue); |
|
853 static void DestroyDT(void* aPropertyValue); |
|
854 |
|
855 #ifdef _MSC_VER |
|
856 // XXX Workaround MSVC issue by making the static FramePropertyDescriptor |
|
857 // non-const. See bug 555727. |
|
858 #define NS_PROPERTY_DESCRIPTOR_CONST |
|
859 #else |
|
860 #define NS_PROPERTY_DESCRIPTOR_CONST const |
|
861 #endif |
|
862 |
|
863 #define NS_DECLARE_FRAME_PROPERTY(prop, dtor) \ |
|
864 static const FramePropertyDescriptor* prop() { \ |
|
865 static NS_PROPERTY_DESCRIPTOR_CONST FramePropertyDescriptor descriptor = { dtor, nullptr }; \ |
|
866 return &descriptor; \ |
|
867 } |
|
868 // Don't use this unless you really know what you're doing! |
|
869 #define NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(prop, dtor) \ |
|
870 static const FramePropertyDescriptor* prop() { \ |
|
871 static NS_PROPERTY_DESCRIPTOR_CONST FramePropertyDescriptor descriptor = { nullptr, dtor }; \ |
|
872 return &descriptor; \ |
|
873 } |
|
874 |
|
875 NS_DECLARE_FRAME_PROPERTY(IBSplitSibling, nullptr) |
|
876 NS_DECLARE_FRAME_PROPERTY(IBSplitPrevSibling, nullptr) |
|
877 |
|
878 NS_DECLARE_FRAME_PROPERTY(NormalPositionProperty, DestroyPoint) |
|
879 NS_DECLARE_FRAME_PROPERTY(ComputedOffsetProperty, DestroyMargin) |
|
880 |
|
881 NS_DECLARE_FRAME_PROPERTY(OutlineInnerRectProperty, DestroyRect) |
|
882 NS_DECLARE_FRAME_PROPERTY(PreEffectsBBoxProperty, DestroyRect) |
|
883 NS_DECLARE_FRAME_PROPERTY(PreTransformOverflowAreasProperty, |
|
884 DestroyOverflowAreas) |
|
885 |
|
886 // The initial overflow area passed to FinishAndStoreOverflow. This is only set |
|
887 // on frames that Preserve3D() or HasPerspective() or IsTransformed(), and |
|
888 // when at least one of the overflow areas differs from the frame bound rect. |
|
889 NS_DECLARE_FRAME_PROPERTY(InitialOverflowProperty, DestroyOverflowAreas) |
|
890 |
|
891 #ifdef DEBUG |
|
892 // InitialOverflowPropertyDebug is added to the frame to indicate that either |
|
893 // the InitialOverflowProperty has been stored or the InitialOverflowProperty |
|
894 // has been suppressed due to being set to the default value (frame bounds) |
|
895 NS_DECLARE_FRAME_PROPERTY(DebugInitialOverflowPropertyApplied, nullptr) |
|
896 #endif |
|
897 |
|
898 NS_DECLARE_FRAME_PROPERTY(UsedMarginProperty, DestroyMargin) |
|
899 NS_DECLARE_FRAME_PROPERTY(UsedPaddingProperty, DestroyMargin) |
|
900 NS_DECLARE_FRAME_PROPERTY(UsedBorderProperty, DestroyMargin) |
|
901 |
|
902 NS_DECLARE_FRAME_PROPERTY(ScrollLayerCount, nullptr) |
|
903 |
|
904 NS_DECLARE_FRAME_PROPERTY(LineBaselineOffset, nullptr) |
|
905 |
|
906 NS_DECLARE_FRAME_PROPERTY(CachedBackgroundImage, DestroySurface) |
|
907 NS_DECLARE_FRAME_PROPERTY(CachedBackgroundImageDT, DestroyDT) |
|
908 |
|
909 NS_DECLARE_FRAME_PROPERTY(InvalidationRect, DestroyRect) |
|
910 |
|
911 NS_DECLARE_FRAME_PROPERTY(RefusedAsyncAnimation, nullptr) |
|
912 |
|
913 /** |
|
914 * Return the distance between the border edge of the frame and the |
|
915 * margin edge of the frame. Like GetRect(), returns the dimensions |
|
916 * as of the most recent reflow. |
|
917 * |
|
918 * This doesn't include any margin collapsing that may have occurred. |
|
919 * |
|
920 * It also treats 'auto' margins as zero, and treats any margins that |
|
921 * should have been turned into 'auto' because of overconstraint as |
|
922 * having their original values. |
|
923 */ |
|
924 virtual nsMargin GetUsedMargin() const; |
|
925 virtual mozilla::LogicalMargin |
|
926 GetLogicalUsedMargin(mozilla::WritingMode aWritingMode) const { |
|
927 return mozilla::LogicalMargin(aWritingMode, GetUsedMargin()); |
|
928 } |
|
929 |
|
930 /** |
|
931 * Return the distance between the border edge of the frame (which is |
|
932 * its rect) and the padding edge of the frame. Like GetRect(), returns |
|
933 * the dimensions as of the most recent reflow. |
|
934 * |
|
935 * Note that this differs from StyleBorder()->GetBorder() in that |
|
936 * this describes region of the frame's box, and |
|
937 * StyleBorder()->GetBorder() describes a border. They differ only |
|
938 * for tables, particularly border-collapse tables. |
|
939 */ |
|
940 virtual nsMargin GetUsedBorder() const; |
|
941 virtual mozilla::LogicalMargin |
|
942 GetLogicalUsedBorder(mozilla::WritingMode aWritingMode) const { |
|
943 return mozilla::LogicalMargin(aWritingMode, GetUsedBorder()); |
|
944 } |
|
945 |
|
946 /** |
|
947 * Return the distance between the padding edge of the frame and the |
|
948 * content edge of the frame. Like GetRect(), returns the dimensions |
|
949 * as of the most recent reflow. |
|
950 */ |
|
951 virtual nsMargin GetUsedPadding() const; |
|
952 virtual mozilla::LogicalMargin |
|
953 GetLogicalUsedPadding(mozilla::WritingMode aWritingMode) const { |
|
954 return mozilla::LogicalMargin(aWritingMode, GetUsedPadding()); |
|
955 } |
|
956 |
|
957 nsMargin GetUsedBorderAndPadding() const { |
|
958 return GetUsedBorder() + GetUsedPadding(); |
|
959 } |
|
960 mozilla::LogicalMargin |
|
961 GetLogicalUsedBorderAndPadding(mozilla::WritingMode aWritingMode) const { |
|
962 return mozilla::LogicalMargin(aWritingMode, GetUsedBorderAndPadding()); |
|
963 } |
|
964 |
|
965 /** |
|
966 * Apply the result of GetSkipSides() on this frame to an nsMargin by |
|
967 * setting to zero any sides that are skipped. |
|
968 * |
|
969 * @param aMargin The margin to apply the result of GetSkipSides() to. |
|
970 * @param aReflowState An optional reflow state parameter, which is used if |
|
971 * ApplySkipSides() is being called in the middle of reflow. |
|
972 * |
|
973 * @note (See also bug 743402, comment 11) GetSkipSides() and its sister |
|
974 * method, ApplySkipSides() checks to see if this frame has a previous |
|
975 * or next continuation to determine if a side should be skipped. |
|
976 * Unfortunately, this only works after reflow has been completed. In |
|
977 * lieu of this, during reflow, an nsHTMLReflowState parameter can be |
|
978 * passed in, indicating that it should be used to determine if sides |
|
979 * should be skipped during reflow. |
|
980 */ |
|
981 void ApplySkipSides(nsMargin& aMargin, |
|
982 const nsHTMLReflowState* aReflowState = nullptr) const; |
|
983 void ApplyLogicalSkipSides(mozilla::LogicalMargin& aMargin, |
|
984 const nsHTMLReflowState* aReflowState = nullptr) const; |
|
985 |
|
986 /** |
|
987 * Like the frame's rect (see |GetRect|), which is the border rect, |
|
988 * other rectangles of the frame, in app units, relative to the parent. |
|
989 */ |
|
990 nsRect GetPaddingRect() const; |
|
991 nsRect GetPaddingRectRelativeToSelf() const; |
|
992 nsRect GetContentRect() const; |
|
993 nsRect GetContentRectRelativeToSelf() const; |
|
994 nsRect GetMarginRectRelativeToSelf() const; |
|
995 |
|
996 /** |
|
997 * The area to paint box-shadows around. The default is the border rect. |
|
998 * (nsFieldSetFrame overrides this). |
|
999 */ |
|
1000 virtual nsRect VisualBorderRectRelativeToSelf() const { |
|
1001 return nsRect(0, 0, mRect.width, mRect.height); |
|
1002 } |
|
1003 |
|
1004 /** |
|
1005 * Get the size, in app units, of the border radii. It returns FALSE iff all |
|
1006 * returned radii == 0 (so no border radii), TRUE otherwise. |
|
1007 * For the aRadii indexes, use the NS_CORNER_* constants in nsStyleConsts.h |
|
1008 * If a side is skipped via aSkipSides, its corners are forced to 0. |
|
1009 * |
|
1010 * All corner radii are then adjusted so they do not require more |
|
1011 * space than aBorderArea, according to the algorithm in css3-background. |
|
1012 * |
|
1013 * aFrameSize is used as the basis for percentage widths and heights. |
|
1014 * aBorderArea is used for the adjustment of radii that might be too |
|
1015 * large. |
|
1016 * FIXME: In the long run, we can probably get away with only one of |
|
1017 * these, especially if we change the way we handle outline-radius (by |
|
1018 * removing it and inflating the border radius) |
|
1019 * |
|
1020 * Return whether any radii are nonzero. |
|
1021 */ |
|
1022 static bool ComputeBorderRadii(const nsStyleCorners& aBorderRadius, |
|
1023 const nsSize& aFrameSize, |
|
1024 const nsSize& aBorderArea, |
|
1025 int aSkipSides, |
|
1026 nscoord aRadii[8]); |
|
1027 |
|
1028 /* |
|
1029 * Given a set of border radii for one box (e.g., border box), convert |
|
1030 * it to the equivalent set of radii for another box (e.g., in to |
|
1031 * padding box, out to outline box) by reducing radii or increasing |
|
1032 * nonzero radii as appropriate. |
|
1033 * |
|
1034 * Indices into aRadii are the NS_CORNER_* constants in nsStyleConsts.h |
|
1035 * |
|
1036 * Note that InsetBorderRadii is lossy, since it can turn nonzero |
|
1037 * radii into zero, and OutsetBorderRadii does not inflate zero radii. |
|
1038 * Therefore, callers should always inset or outset directly from the |
|
1039 * original value coming from style. |
|
1040 */ |
|
1041 static void InsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets); |
|
1042 static void OutsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets); |
|
1043 |
|
1044 /** |
|
1045 * Fill in border radii for this frame. Return whether any are |
|
1046 * nonzero. |
|
1047 * |
|
1048 * Indices into aRadii are the NS_CORNER_* constants in nsStyleConsts.h |
|
1049 */ |
|
1050 virtual bool GetBorderRadii(nscoord aRadii[8]) const; |
|
1051 |
|
1052 bool GetPaddingBoxBorderRadii(nscoord aRadii[8]) const; |
|
1053 bool GetContentBoxBorderRadii(nscoord aRadii[8]) const; |
|
1054 |
|
1055 /** |
|
1056 * Get the position of the frame's baseline, relative to the top of |
|
1057 * the frame (its top border edge). Only valid when Reflow is not |
|
1058 * needed. |
|
1059 */ |
|
1060 virtual nscoord GetBaseline() const = 0; |
|
1061 |
|
1062 /** |
|
1063 * Get the position of the baseline on which the caret needs to be placed, |
|
1064 * relative to the top of the frame. This is mostly needed for frames |
|
1065 * which return a baseline from GetBaseline which is not useful for |
|
1066 * caret positioning. |
|
1067 */ |
|
1068 virtual nscoord GetCaretBaseline() const { |
|
1069 return GetBaseline(); |
|
1070 } |
|
1071 |
|
1072 /** |
|
1073 * Get the specified child list. |
|
1074 * |
|
1075 * @param aListID identifies the requested child list. |
|
1076 * @return the child list. If the requested list is unsupported by this |
|
1077 * frame type, an empty list will be returned. |
|
1078 */ |
|
1079 virtual const nsFrameList& GetChildList(ChildListID aListID) const = 0; |
|
1080 const nsFrameList& PrincipalChildList() { return GetChildList(kPrincipalList); } |
|
1081 virtual void GetChildLists(nsTArray<ChildList>* aLists) const = 0; |
|
1082 |
|
1083 /** |
|
1084 * Gets the child lists for this frame, including |
|
1085 * ones belong to a child document. |
|
1086 */ |
|
1087 void GetCrossDocChildLists(nsTArray<ChildList>* aLists); |
|
1088 |
|
1089 // XXXbz this method should go away |
|
1090 nsIFrame* GetFirstChild(ChildListID aListID) const { |
|
1091 return GetChildList(aListID).FirstChild(); |
|
1092 } |
|
1093 // XXXmats this method should also go away then |
|
1094 nsIFrame* GetLastChild(ChildListID aListID) const { |
|
1095 return GetChildList(aListID).LastChild(); |
|
1096 } |
|
1097 nsIFrame* GetFirstPrincipalChild() const { |
|
1098 return GetFirstChild(kPrincipalList); |
|
1099 } |
|
1100 |
|
1101 // The individual concrete child lists. |
|
1102 static const ChildListID kPrincipalList = mozilla::layout::kPrincipalList; |
|
1103 static const ChildListID kAbsoluteList = mozilla::layout::kAbsoluteList; |
|
1104 static const ChildListID kBulletList = mozilla::layout::kBulletList; |
|
1105 static const ChildListID kCaptionList = mozilla::layout::kCaptionList; |
|
1106 static const ChildListID kColGroupList = mozilla::layout::kColGroupList; |
|
1107 static const ChildListID kExcessOverflowContainersList = mozilla::layout::kExcessOverflowContainersList; |
|
1108 static const ChildListID kFixedList = mozilla::layout::kFixedList; |
|
1109 static const ChildListID kFloatList = mozilla::layout::kFloatList; |
|
1110 static const ChildListID kOverflowContainersList = mozilla::layout::kOverflowContainersList; |
|
1111 static const ChildListID kOverflowList = mozilla::layout::kOverflowList; |
|
1112 static const ChildListID kOverflowOutOfFlowList = mozilla::layout::kOverflowOutOfFlowList; |
|
1113 static const ChildListID kPopupList = mozilla::layout::kPopupList; |
|
1114 static const ChildListID kPushedFloatsList = mozilla::layout::kPushedFloatsList; |
|
1115 static const ChildListID kSelectPopupList = mozilla::layout::kSelectPopupList; |
|
1116 // A special alias for kPrincipalList that do not request reflow. |
|
1117 static const ChildListID kNoReflowPrincipalList = mozilla::layout::kNoReflowPrincipalList; |
|
1118 |
|
1119 /** |
|
1120 * Child frames are linked together in a doubly-linked list |
|
1121 */ |
|
1122 nsIFrame* GetNextSibling() const { return mNextSibling; } |
|
1123 void SetNextSibling(nsIFrame* aNextSibling) { |
|
1124 NS_ASSERTION(this != aNextSibling, "Creating a circular frame list, this is very bad."); |
|
1125 if (mNextSibling && mNextSibling->GetPrevSibling() == this) { |
|
1126 mNextSibling->mPrevSibling = nullptr; |
|
1127 } |
|
1128 mNextSibling = aNextSibling; |
|
1129 if (mNextSibling) { |
|
1130 mNextSibling->mPrevSibling = this; |
|
1131 } |
|
1132 } |
|
1133 |
|
1134 nsIFrame* GetPrevSibling() const { return mPrevSibling; } |
|
1135 |
|
1136 /** |
|
1137 * Builds the display lists for the content represented by this frame |
|
1138 * and its descendants. The background+borders of this element must |
|
1139 * be added first, before any other content. |
|
1140 * |
|
1141 * This should only be called by methods in nsFrame. Instead of calling this |
|
1142 * directly, call either BuildDisplayListForStackingContext or |
|
1143 * BuildDisplayListForChild. |
|
1144 * |
|
1145 * See nsDisplayList.h for more information about display lists. |
|
1146 * |
|
1147 * @param aDirtyRect content outside this rectangle can be ignored; the |
|
1148 * rectangle is in frame coordinates |
|
1149 */ |
|
1150 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, |
|
1151 const nsRect& aDirtyRect, |
|
1152 const nsDisplayListSet& aLists) {} |
|
1153 /** |
|
1154 * Displays the caret onto the given display list builder. The caret is |
|
1155 * painted on top of the rest of the display list items. |
|
1156 * |
|
1157 * @param aDirtyRect is the dirty rectangle that we're repainting. |
|
1158 */ |
|
1159 void DisplayCaret(nsDisplayListBuilder* aBuilder, |
|
1160 const nsRect& aDirtyRect, |
|
1161 nsDisplayList* aList); |
|
1162 |
|
1163 /** |
|
1164 * Get the preferred caret color at the offset. |
|
1165 * |
|
1166 * @param aOffset is offset of the content. |
|
1167 */ |
|
1168 virtual nscolor GetCaretColorAt(int32_t aOffset); |
|
1169 |
|
1170 |
|
1171 bool IsThemed(nsITheme::Transparency* aTransparencyState = nullptr) const { |
|
1172 return IsThemed(StyleDisplay(), aTransparencyState); |
|
1173 } |
|
1174 bool IsThemed(const nsStyleDisplay* aDisp, |
|
1175 nsITheme::Transparency* aTransparencyState = nullptr) const { |
|
1176 nsIFrame* mutable_this = const_cast<nsIFrame*>(this); |
|
1177 if (!aDisp->mAppearance) |
|
1178 return false; |
|
1179 nsPresContext* pc = PresContext(); |
|
1180 nsITheme *theme = pc->GetTheme(); |
|
1181 if(!theme || |
|
1182 !theme->ThemeSupportsWidget(pc, mutable_this, aDisp->mAppearance)) |
|
1183 return false; |
|
1184 if (aTransparencyState) { |
|
1185 *aTransparencyState = |
|
1186 theme->GetWidgetTransparency(mutable_this, aDisp->mAppearance); |
|
1187 } |
|
1188 return true; |
|
1189 } |
|
1190 |
|
1191 /** |
|
1192 * Builds a display list for the content represented by this frame, |
|
1193 * treating this frame as the root of a stacking context. |
|
1194 * @param aDirtyRect content outside this rectangle can be ignored; the |
|
1195 * rectangle is in frame coordinates |
|
1196 */ |
|
1197 void BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, |
|
1198 const nsRect& aDirtyRect, |
|
1199 nsDisplayList* aList); |
|
1200 |
|
1201 enum { |
|
1202 DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT = 0x01, |
|
1203 DISPLAY_CHILD_FORCE_STACKING_CONTEXT = 0x02, |
|
1204 DISPLAY_CHILD_INLINE = 0x04 |
|
1205 }; |
|
1206 /** |
|
1207 * Adjusts aDirtyRect for the child's offset, checks that the dirty rect |
|
1208 * actually intersects the child (or its descendants), calls BuildDisplayList |
|
1209 * on the child if necessary, and puts things in the right lists if the child |
|
1210 * is positioned. |
|
1211 * |
|
1212 * @param aFlags combination of DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT, |
|
1213 * DISPLAY_CHILD_FORCE_STACKING_CONTEXT and DISPLAY_CHILD_INLINE |
|
1214 */ |
|
1215 void BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, |
|
1216 nsIFrame* aChild, |
|
1217 const nsRect& aDirtyRect, |
|
1218 const nsDisplayListSet& aLists, |
|
1219 uint32_t aFlags = 0); |
|
1220 |
|
1221 /** |
|
1222 * Does this frame need a view? |
|
1223 */ |
|
1224 virtual bool NeedsView() { return false; } |
|
1225 |
|
1226 /** |
|
1227 * Returns true if this frame is transformed (e.g. has CSS or SVG transforms) |
|
1228 * or if its parent is an SVG frame that has children-only transforms (e.g. |
|
1229 * an SVG viewBox attribute). |
|
1230 */ |
|
1231 bool IsTransformed() const; |
|
1232 |
|
1233 /** |
|
1234 * Returns true if the frame is translucent for the purposes of creating a |
|
1235 * stacking context. |
|
1236 */ |
|
1237 bool HasOpacity() const |
|
1238 { |
|
1239 return HasOpacityInternal(1.0f); |
|
1240 } |
|
1241 /** |
|
1242 * Returns true if the frame is translucent for display purposes. |
|
1243 */ |
|
1244 bool HasVisualOpacity() const |
|
1245 { |
|
1246 // Treat an opacity value of 0.99 and above as opaque. This is an |
|
1247 // optimization aimed at Web content which use opacity:0.99 as a hint for |
|
1248 // creating a stacking context only. |
|
1249 return HasOpacityInternal(0.99f); |
|
1250 } |
|
1251 |
|
1252 /** |
|
1253 * Return true if this frame might be using a transform getter. |
|
1254 */ |
|
1255 virtual bool HasTransformGetter() const { return false; } |
|
1256 |
|
1257 /** |
|
1258 * Returns true if this frame is an SVG frame that has SVG transforms applied |
|
1259 * to it, or if its parent frame is an SVG frame that has children-only |
|
1260 * transforms (e.g. an SVG viewBox attribute). |
|
1261 * If aOwnTransforms is non-null and the frame has its own SVG transforms, |
|
1262 * aOwnTransforms will be set to these transforms. If aFromParentTransforms |
|
1263 * is non-null and the frame has an SVG parent with children-only transforms, |
|
1264 * then aFromParentTransforms will be set to these transforms. |
|
1265 */ |
|
1266 virtual bool IsSVGTransformed(Matrix *aOwnTransforms = nullptr, |
|
1267 Matrix *aFromParentTransforms = nullptr) const; |
|
1268 |
|
1269 /** |
|
1270 * Returns whether this frame will attempt to preserve the 3d transforms of its |
|
1271 * children. This requires transform-style: preserve-3d, as well as no clipping |
|
1272 * or svg effects. |
|
1273 */ |
|
1274 bool Preserves3DChildren() const; |
|
1275 |
|
1276 /** |
|
1277 * Returns whether this frame has a parent that Preserves3DChildren() and has |
|
1278 * its own transform (or hidden backface) to be combined with the parent's |
|
1279 * transform. |
|
1280 */ |
|
1281 bool Preserves3D() const; |
|
1282 |
|
1283 bool HasPerspective() const; |
|
1284 |
|
1285 bool ChildrenHavePerspective() const; |
|
1286 |
|
1287 // Calculate the overflow size of all child frames, taking preserve-3d into account |
|
1288 void ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, const nsRect& aBounds); |
|
1289 |
|
1290 void RecomputePerspectiveChildrenOverflow(const nsStyleContext* aStartStyle, const nsRect* aBounds); |
|
1291 |
|
1292 /** |
|
1293 * Returns the number of ancestors between this and the root of our frame tree |
|
1294 */ |
|
1295 uint32_t GetDepthInFrameTree() { |
|
1296 uint32_t result = 0; |
|
1297 for (nsIFrame* ancestor = GetParent(); ancestor; |
|
1298 ancestor = ancestor->GetParent()) { |
|
1299 result++; |
|
1300 } |
|
1301 return result; |
|
1302 } |
|
1303 |
|
1304 /** |
|
1305 * Event handling of GUI events. |
|
1306 * |
|
1307 * @param aEvent event structure describing the type of event and rge widget |
|
1308 * where the event originated |
|
1309 * The |point| member of this is in the coordinate system of the |
|
1310 * view returned by GetOffsetFromView. |
|
1311 * @param aEventStatus a return value indicating whether the event was handled |
|
1312 * and whether default processing should be done |
|
1313 * |
|
1314 * XXX From a frame's perspective it's unclear what the effect of the event status |
|
1315 * is. Does it cause the event to continue propagating through the frame hierarchy |
|
1316 * or is it just returned to the widgets? |
|
1317 * |
|
1318 * @see WidgetGUIEvent |
|
1319 * @see nsEventStatus |
|
1320 */ |
|
1321 virtual nsresult HandleEvent(nsPresContext* aPresContext, |
|
1322 mozilla::WidgetGUIEvent* aEvent, |
|
1323 nsEventStatus* aEventStatus) = 0; |
|
1324 |
|
1325 virtual nsresult GetContentForEvent(mozilla::WidgetEvent* aEvent, |
|
1326 nsIContent** aContent) = 0; |
|
1327 |
|
1328 // This structure keeps track of the content node and offsets associated with |
|
1329 // a point; there is a primary and a secondary offset associated with any |
|
1330 // point. The primary and secondary offsets differ when the point is over a |
|
1331 // non-text object. The primary offset is the expected position of the |
|
1332 // cursor calculated from a point; the secondary offset, when it is different, |
|
1333 // indicates that the point is in the boundaries of some selectable object. |
|
1334 // Note that the primary offset can be after the secondary offset; for places |
|
1335 // that need the beginning and end of the object, the StartOffset and |
|
1336 // EndOffset helpers can be used. |
|
1337 struct MOZ_STACK_CLASS ContentOffsets { |
|
1338 ContentOffsets(); |
|
1339 ContentOffsets(const ContentOffsets&); |
|
1340 ~ContentOffsets(); |
|
1341 nsCOMPtr<nsIContent> content; |
|
1342 bool IsNull() { return !content; } |
|
1343 int32_t offset; |
|
1344 int32_t secondaryOffset; |
|
1345 // Helpers for places that need the ends of the offsets and expect them in |
|
1346 // numerical order, as opposed to wanting the primary and secondary offsets |
|
1347 int32_t StartOffset() { return std::min(offset, secondaryOffset); } |
|
1348 int32_t EndOffset() { return std::max(offset, secondaryOffset); } |
|
1349 // This boolean indicates whether the associated content is before or after |
|
1350 // the offset; the most visible use is to allow the caret to know which line |
|
1351 // to display on. |
|
1352 bool associateWithNext; |
|
1353 }; |
|
1354 enum { |
|
1355 IGNORE_SELECTION_STYLE = 0x01, |
|
1356 // Treat visibility:hidden frames as non-selectable |
|
1357 SKIP_HIDDEN = 0x02 |
|
1358 }; |
|
1359 /** |
|
1360 * This function calculates the content offsets for selection relative to |
|
1361 * a point. Note that this should generally only be callled on the event |
|
1362 * frame associated with an event because this function does not account |
|
1363 * for frame lists other than the primary one. |
|
1364 * @param aPoint point relative to this frame |
|
1365 */ |
|
1366 ContentOffsets GetContentOffsetsFromPoint(nsPoint aPoint, |
|
1367 uint32_t aFlags = 0); |
|
1368 |
|
1369 virtual ContentOffsets GetContentOffsetsFromPointExternal(nsPoint aPoint, |
|
1370 uint32_t aFlags = 0) |
|
1371 { return GetContentOffsetsFromPoint(aPoint, aFlags); } |
|
1372 |
|
1373 /** |
|
1374 * Ensure that aImage gets notifed when the underlying image request loads |
|
1375 * or animates. |
|
1376 */ |
|
1377 void AssociateImage(const nsStyleImage& aImage, nsPresContext* aPresContext); |
|
1378 |
|
1379 /** |
|
1380 * This structure holds information about a cursor. mContainer represents a |
|
1381 * loaded image that should be preferred. If it is not possible to use it, or |
|
1382 * if it is null, mCursor should be used. |
|
1383 */ |
|
1384 struct MOZ_STACK_CLASS Cursor { |
|
1385 nsCOMPtr<imgIContainer> mContainer; |
|
1386 int32_t mCursor; |
|
1387 bool mHaveHotspot; |
|
1388 float mHotspotX, mHotspotY; |
|
1389 }; |
|
1390 /** |
|
1391 * Get the cursor for a given frame. |
|
1392 */ |
|
1393 virtual nsresult GetCursor(const nsPoint& aPoint, |
|
1394 Cursor& aCursor) = 0; |
|
1395 |
|
1396 /** |
|
1397 * Get a point (in the frame's coordinate space) given an offset into |
|
1398 * the content. This point should be on the baseline of text with |
|
1399 * the correct horizontal offset |
|
1400 */ |
|
1401 virtual nsresult GetPointFromOffset(int32_t inOffset, |
|
1402 nsPoint* outPoint) = 0; |
|
1403 |
|
1404 /** |
|
1405 * Get the child frame of this frame which contains the given |
|
1406 * content offset. outChildFrame may be this frame, or nullptr on return. |
|
1407 * outContentOffset returns the content offset relative to the start |
|
1408 * of the returned node. You can also pass a hint which tells the method |
|
1409 * to stick to the end of the first found frame or the beginning of the |
|
1410 * next in case the offset falls on a boundary. |
|
1411 */ |
|
1412 virtual nsresult GetChildFrameContainingOffset(int32_t inContentOffset, |
|
1413 bool inHint,//false stick left |
|
1414 int32_t* outFrameContentOffset, |
|
1415 nsIFrame** outChildFrame) = 0; |
|
1416 |
|
1417 /** |
|
1418 * Get the current frame-state value for this frame. aResult is |
|
1419 * filled in with the state bits. |
|
1420 */ |
|
1421 nsFrameState GetStateBits() const { return mState; } |
|
1422 |
|
1423 /** |
|
1424 * Update the current frame-state value for this frame. |
|
1425 */ |
|
1426 void AddStateBits(nsFrameState aBits) { mState |= aBits; } |
|
1427 void RemoveStateBits(nsFrameState aBits) { mState &= ~aBits; } |
|
1428 |
|
1429 /** |
|
1430 * Checks if the current frame-state includes all of the listed bits |
|
1431 */ |
|
1432 bool HasAllStateBits(nsFrameState aBits) const |
|
1433 { |
|
1434 return (mState & aBits) == aBits; |
|
1435 } |
|
1436 |
|
1437 /** |
|
1438 * Checks if the current frame-state includes any of the listed bits |
|
1439 */ |
|
1440 bool HasAnyStateBits(nsFrameState aBits) const |
|
1441 { |
|
1442 return mState & aBits; |
|
1443 } |
|
1444 |
|
1445 /** |
|
1446 * This call is invoked on the primary frame for a character data content |
|
1447 * node, when it is changed in the content tree. |
|
1448 */ |
|
1449 virtual nsresult CharacterDataChanged(CharacterDataChangeInfo* aInfo) = 0; |
|
1450 |
|
1451 /** |
|
1452 * This call is invoked when the value of a content objects's attribute |
|
1453 * is changed. |
|
1454 * The first frame that maps that content is asked to deal |
|
1455 * with the change by doing whatever is appropriate. |
|
1456 * |
|
1457 * @param aNameSpaceID the namespace of the attribute |
|
1458 * @param aAttribute the atom name of the attribute |
|
1459 * @param aModType Whether or not the attribute was added, changed, or removed. |
|
1460 * The constants are defined in nsIDOMMutationEvent.h. |
|
1461 */ |
|
1462 virtual nsresult AttributeChanged(int32_t aNameSpaceID, |
|
1463 nsIAtom* aAttribute, |
|
1464 int32_t aModType) = 0; |
|
1465 |
|
1466 /** |
|
1467 * When the content states of a content object change, this method is invoked |
|
1468 * on the primary frame of that content object. |
|
1469 * |
|
1470 * @param aStates the changed states |
|
1471 */ |
|
1472 virtual void ContentStatesChanged(mozilla::EventStates aStates); |
|
1473 |
|
1474 /** |
|
1475 * Return how your frame can be split. |
|
1476 */ |
|
1477 virtual nsSplittableType GetSplittableType() const = 0; |
|
1478 |
|
1479 /** |
|
1480 * Continuation member functions |
|
1481 */ |
|
1482 virtual nsIFrame* GetPrevContinuation() const = 0; |
|
1483 virtual void SetPrevContinuation(nsIFrame*) = 0; |
|
1484 virtual nsIFrame* GetNextContinuation() const = 0; |
|
1485 virtual void SetNextContinuation(nsIFrame*) = 0; |
|
1486 virtual nsIFrame* FirstContinuation() const { |
|
1487 return const_cast<nsIFrame*>(this); |
|
1488 } |
|
1489 virtual nsIFrame* LastContinuation() const { |
|
1490 return const_cast<nsIFrame*>(this); |
|
1491 } |
|
1492 |
|
1493 /** |
|
1494 * GetTailContinuation gets the last non-overflow-container continuation |
|
1495 * in the continuation chain, i.e. where the next sibling element |
|
1496 * should attach). |
|
1497 */ |
|
1498 nsIFrame* GetTailContinuation(); |
|
1499 |
|
1500 /** |
|
1501 * Flow member functions |
|
1502 */ |
|
1503 virtual nsIFrame* GetPrevInFlowVirtual() const = 0; |
|
1504 nsIFrame* GetPrevInFlow() const { return GetPrevInFlowVirtual(); } |
|
1505 virtual void SetPrevInFlow(nsIFrame*) = 0; |
|
1506 |
|
1507 virtual nsIFrame* GetNextInFlowVirtual() const = 0; |
|
1508 nsIFrame* GetNextInFlow() const { return GetNextInFlowVirtual(); } |
|
1509 virtual void SetNextInFlow(nsIFrame*) = 0; |
|
1510 |
|
1511 /** |
|
1512 * Return the first frame in our current flow. |
|
1513 */ |
|
1514 virtual nsIFrame* FirstInFlow() const { |
|
1515 return const_cast<nsIFrame*>(this); |
|
1516 } |
|
1517 |
|
1518 /** |
|
1519 * Return the last frame in our current flow. |
|
1520 */ |
|
1521 virtual nsIFrame* LastInFlow() const { |
|
1522 return const_cast<nsIFrame*>(this); |
|
1523 } |
|
1524 |
|
1525 |
|
1526 /** |
|
1527 * Mark any stored intrinsic width information as dirty (requiring |
|
1528 * re-calculation). Note that this should generally not be called |
|
1529 * directly; nsPresShell::FrameNeedsReflow will call it instead. |
|
1530 */ |
|
1531 virtual void MarkIntrinsicWidthsDirty() = 0; |
|
1532 |
|
1533 /** |
|
1534 * Get the intrinsic minimum width of the frame. This must be less |
|
1535 * than or equal to the intrinsic width. |
|
1536 * |
|
1537 * This is *not* affected by the CSS 'min-width', 'width', and |
|
1538 * 'max-width' properties on this frame, but it is affected by the |
|
1539 * values of those properties on this frame's descendants. (It may be |
|
1540 * called during computation of the values of those properties, so it |
|
1541 * cannot depend on any values in the nsStylePosition for this frame.) |
|
1542 * |
|
1543 * The value returned should **NOT** include the space required for |
|
1544 * padding and border. |
|
1545 * |
|
1546 * Note that many frames will cache the result of this function call |
|
1547 * unless MarkIntrinsicWidthsDirty is called. |
|
1548 * |
|
1549 * It is not acceptable for a frame to mark itself dirty when this |
|
1550 * method is called. |
|
1551 * |
|
1552 * This method must not return a negative value. |
|
1553 */ |
|
1554 virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) = 0; |
|
1555 |
|
1556 /** |
|
1557 * Get the intrinsic width of the frame. This must be greater than or |
|
1558 * equal to the intrinsic minimum width. |
|
1559 * |
|
1560 * Otherwise, all the comments for |GetMinWidth| above apply. |
|
1561 */ |
|
1562 virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) = 0; |
|
1563 |
|
1564 /** |
|
1565 * |InlineIntrinsicWidth| represents the intrinsic width information |
|
1566 * in inline layout. Code that determines the intrinsic width of a |
|
1567 * region of inline layout accumulates the result into this structure. |
|
1568 * This pattern is needed because we need to maintain state |
|
1569 * information about whitespace (for both collapsing and trimming). |
|
1570 */ |
|
1571 struct InlineIntrinsicWidthData { |
|
1572 InlineIntrinsicWidthData() |
|
1573 : line(nullptr) |
|
1574 , lineContainer(nullptr) |
|
1575 , prevLines(0) |
|
1576 , currentLine(0) |
|
1577 , skipWhitespace(true) |
|
1578 , trailingWhitespace(0) |
|
1579 {} |
|
1580 |
|
1581 // The line. This may be null if the inlines are not associated with |
|
1582 // a block or if we just don't know the line. |
|
1583 const nsLineList_iterator* line; |
|
1584 |
|
1585 // The line container. |
|
1586 nsIFrame* lineContainer; |
|
1587 |
|
1588 // The maximum intrinsic width for all previous lines. |
|
1589 nscoord prevLines; |
|
1590 |
|
1591 // The maximum intrinsic width for the current line. At a line |
|
1592 // break (mandatory for preferred width; allowed for minimum width), |
|
1593 // the caller should call |Break()|. |
|
1594 nscoord currentLine; |
|
1595 |
|
1596 // True if initial collapsable whitespace should be skipped. This |
|
1597 // should be true at the beginning of a block, after hard breaks |
|
1598 // and when the last text ended with whitespace. |
|
1599 bool skipWhitespace; |
|
1600 |
|
1601 // This contains the width of the trimmable whitespace at the end of |
|
1602 // |currentLine|; it is zero if there is no such whitespace. |
|
1603 nscoord trailingWhitespace; |
|
1604 |
|
1605 // Floats encountered in the lines. |
|
1606 class FloatInfo { |
|
1607 public: |
|
1608 FloatInfo(const nsIFrame* aFrame, nscoord aWidth) |
|
1609 : mFrame(aFrame), mWidth(aWidth) |
|
1610 { } |
|
1611 const nsIFrame* Frame() const { return mFrame; } |
|
1612 nscoord Width() const { return mWidth; } |
|
1613 |
|
1614 private: |
|
1615 const nsIFrame* mFrame; |
|
1616 nscoord mWidth; |
|
1617 }; |
|
1618 |
|
1619 nsTArray<FloatInfo> floats; |
|
1620 }; |
|
1621 |
|
1622 struct InlineMinWidthData : public InlineIntrinsicWidthData { |
|
1623 InlineMinWidthData() |
|
1624 : trailingTextFrame(nullptr) |
|
1625 , atStartOfLine(true) |
|
1626 {} |
|
1627 |
|
1628 // We need to distinguish forced and optional breaks for cases where the |
|
1629 // current line total is negative. When it is, we need to ignore |
|
1630 // optional breaks to prevent min-width from ending up bigger than |
|
1631 // pref-width. |
|
1632 void ForceBreak(nsRenderingContext *aRenderingContext); |
|
1633 |
|
1634 // If the break here is actually taken, aHyphenWidth must be added to the |
|
1635 // width of the current line. |
|
1636 void OptionallyBreak(nsRenderingContext *aRenderingContext, |
|
1637 nscoord aHyphenWidth = 0); |
|
1638 |
|
1639 // The last text frame processed so far in the current line, when |
|
1640 // the last characters in that text frame are relevant for line |
|
1641 // break opportunities. |
|
1642 nsIFrame *trailingTextFrame; |
|
1643 |
|
1644 // Whether we're currently at the start of the line. If we are, we |
|
1645 // can't break (for example, between the text-indent and the first |
|
1646 // word). |
|
1647 bool atStartOfLine; |
|
1648 }; |
|
1649 |
|
1650 struct InlinePrefWidthData : public InlineIntrinsicWidthData { |
|
1651 void ForceBreak(nsRenderingContext *aRenderingContext); |
|
1652 }; |
|
1653 |
|
1654 /** |
|
1655 * Add the intrinsic minimum width of a frame in a way suitable for |
|
1656 * use in inline layout to an |InlineIntrinsicWidthData| object that |
|
1657 * represents the intrinsic width information of all the previous |
|
1658 * frames in the inline layout region. |
|
1659 * |
|
1660 * All *allowed* breakpoints within the frame determine what counts as |
|
1661 * a line for the |InlineIntrinsicWidthData|. This means that |
|
1662 * |aData->trailingWhitespace| will always be zero (unlike for |
|
1663 * AddInlinePrefWidth). |
|
1664 * |
|
1665 * All the comments for |GetMinWidth| apply, except that this function |
|
1666 * is responsible for adding padding, border, and margin and for |
|
1667 * considering the effects of 'width', 'min-width', and 'max-width'. |
|
1668 * |
|
1669 * This may be called on any frame. Frames that do not participate in |
|
1670 * line breaking can inherit the default implementation on nsFrame, |
|
1671 * which calls |GetMinWidth|. |
|
1672 */ |
|
1673 virtual void |
|
1674 AddInlineMinWidth(nsRenderingContext *aRenderingContext, |
|
1675 InlineMinWidthData *aData) = 0; |
|
1676 |
|
1677 /** |
|
1678 * Add the intrinsic preferred width of a frame in a way suitable for |
|
1679 * use in inline layout to an |InlineIntrinsicWidthData| object that |
|
1680 * represents the intrinsic width information of all the previous |
|
1681 * frames in the inline layout region. |
|
1682 * |
|
1683 * All the comments for |AddInlineMinWidth| and |GetPrefWidth| apply, |
|
1684 * except that this fills in an |InlineIntrinsicWidthData| structure |
|
1685 * based on using all *mandatory* breakpoints within the frame. |
|
1686 */ |
|
1687 virtual void |
|
1688 AddInlinePrefWidth(nsRenderingContext *aRenderingContext, |
|
1689 InlinePrefWidthData *aData) = 0; |
|
1690 |
|
1691 /** |
|
1692 * Return the horizontal components of padding, border, and margin |
|
1693 * that contribute to the intrinsic width that applies to the parent. |
|
1694 */ |
|
1695 struct IntrinsicWidthOffsetData { |
|
1696 nscoord hPadding, hBorder, hMargin; |
|
1697 float hPctPadding, hPctMargin; |
|
1698 |
|
1699 IntrinsicWidthOffsetData() |
|
1700 : hPadding(0), hBorder(0), hMargin(0) |
|
1701 , hPctPadding(0.0f), hPctMargin(0.0f) |
|
1702 {} |
|
1703 }; |
|
1704 virtual IntrinsicWidthOffsetData |
|
1705 IntrinsicWidthOffsets(nsRenderingContext* aRenderingContext) = 0; |
|
1706 |
|
1707 virtual mozilla::IntrinsicSize GetIntrinsicSize() = 0; |
|
1708 |
|
1709 /* |
|
1710 * Get the intrinsic ratio of this element, or nsSize(0,0) if it has |
|
1711 * no intrinsic ratio. The intrinsic ratio is the ratio of the |
|
1712 * height/width of a box with an intrinsic size or the intrinsic |
|
1713 * aspect ratio of a scalable vector image without an intrinsic size. |
|
1714 * |
|
1715 * Either one of the sides may be zero, indicating a zero or infinite |
|
1716 * ratio. |
|
1717 */ |
|
1718 virtual nsSize GetIntrinsicRatio() = 0; |
|
1719 |
|
1720 /** |
|
1721 * Bit-flags to pass to ComputeSize in |aFlags| parameter. |
|
1722 */ |
|
1723 enum { |
|
1724 /* Set if the frame is in a context where non-replaced blocks should |
|
1725 * shrink-wrap (e.g., it's floating, absolutely positioned, or |
|
1726 * inline-block). */ |
|
1727 eShrinkWrap = 1 << 0, |
|
1728 /* Set if we'd like to compute our 'auto' height, regardless of our actual |
|
1729 * computed value of 'height'. (e.g. to get an intrinsic height for flex |
|
1730 * items with "min-height: auto" to use during flexbox layout.) */ |
|
1731 eUseAutoHeight = 1 << 1 |
|
1732 }; |
|
1733 |
|
1734 /** |
|
1735 * Compute the size that a frame will occupy. Called while |
|
1736 * constructing the nsHTMLReflowState to be used to Reflow the frame, |
|
1737 * in order to fill its mComputedWidth and mComputedHeight member |
|
1738 * variables. |
|
1739 * |
|
1740 * The |height| member of the return value may be |
|
1741 * NS_UNCONSTRAINEDSIZE, but the |width| member must not be. |
|
1742 * |
|
1743 * Note that the reason that border and padding need to be passed |
|
1744 * separately is so that the 'box-sizing' property can be handled. |
|
1745 * Thus aMargin includes absolute positioning offsets as well. |
|
1746 * |
|
1747 * @param aCBSize The size of the element's containing block. (Well, |
|
1748 * the |height| component isn't really.) |
|
1749 * @param aAvailableWidth The available width for 'auto' widths. |
|
1750 * This is usually the same as aCBSize.width, |
|
1751 * but differs in cases such as block |
|
1752 * formatting context roots next to floats, or |
|
1753 * in some cases of float reflow in quirks |
|
1754 * mode. |
|
1755 * @param aMargin The sum of the vertical / horizontal margins |
|
1756 * ***AND*** absolute positioning offsets (top, right, |
|
1757 * bottom, left) of the frame, including actual values |
|
1758 * resulting from percentages and from the |
|
1759 * "hypothetical box" for absolute positioning, but |
|
1760 * not including actual values resulting from 'auto' |
|
1761 * margins or ignored 'auto' values in absolute |
|
1762 * positioning. |
|
1763 * @param aBorder The sum of the vertical / horizontal border widths |
|
1764 * of the frame. |
|
1765 * @param aPadding The sum of the vertical / horizontal margins of |
|
1766 * the frame, including actual values resulting from |
|
1767 * percentages. |
|
1768 * @param aFlags Flags to further customize behavior (definitions above). |
|
1769 */ |
|
1770 virtual nsSize ComputeSize(nsRenderingContext *aRenderingContext, |
|
1771 nsSize aCBSize, nscoord aAvailableWidth, |
|
1772 nsSize aMargin, nsSize aBorder, nsSize aPadding, |
|
1773 uint32_t aFlags) = 0; |
|
1774 |
|
1775 /** |
|
1776 * Compute a tight bounding rectangle for the frame. This is a rectangle |
|
1777 * that encloses the pixels that are actually drawn. We're allowed to be |
|
1778 * conservative and currently we don't try very hard. The rectangle is |
|
1779 * in appunits and relative to the origin of this frame. |
|
1780 * |
|
1781 * This probably only needs to include frame bounds, glyph bounds, and |
|
1782 * text decorations, but today it sometimes includes other things that |
|
1783 * contribute to visual overflow. |
|
1784 * |
|
1785 * @param aContext a rendering context that can be used if we need |
|
1786 * to do measurement |
|
1787 */ |
|
1788 virtual nsRect ComputeTightBounds(gfxContext* aContext) const; |
|
1789 |
|
1790 /** |
|
1791 * This function is similar to GetPrefWidth and ComputeTightBounds: it |
|
1792 * computes the left and right coordinates of a preferred tight bounding |
|
1793 * rectangle for the frame. This is a rectangle that would enclose the pixels |
|
1794 * that are drawn if we lay out the element without taking any optional line |
|
1795 * breaks. The rectangle is in appunits and relative to the origin of this |
|
1796 * frame. Currently, this function is only implemented for nsBlockFrame and |
|
1797 * nsTextFrame and is used to determine intrinsic widths of MathML token |
|
1798 * elements. |
|
1799 |
|
1800 * @param aContext a rendering context that can be used if we need |
|
1801 * to do measurement |
|
1802 * @param aX computed left coordinate of the tight bounding rectangle |
|
1803 * @param aXMost computed intrinsic width of the tight bounding rectangle |
|
1804 * |
|
1805 */ |
|
1806 virtual nsresult GetPrefWidthTightBounds(nsRenderingContext* aContext, |
|
1807 nscoord* aX, |
|
1808 nscoord* aXMost); |
|
1809 |
|
1810 /** |
|
1811 * Pre-reflow hook. Before a frame is reflowed this method will be called. |
|
1812 * This call will always be invoked at least once before a subsequent Reflow |
|
1813 * and DidReflow call. It may be called more than once, In general you will |
|
1814 * receive on WillReflow notification before each Reflow request. |
|
1815 * |
|
1816 * XXX Is this really the semantics we want? Because we have the NS_FRAME_IN_REFLOW |
|
1817 * bit we can ensure we don't call it more than once... |
|
1818 */ |
|
1819 virtual nsresult WillReflow(nsPresContext* aPresContext) = 0; |
|
1820 |
|
1821 /** |
|
1822 * The frame is given an available size and asked for its desired |
|
1823 * size. This is the frame's opportunity to reflow its children. |
|
1824 * |
|
1825 * If the frame has the NS_FRAME_IS_DIRTY bit set then it is |
|
1826 * responsible for completely reflowing itself and all of its |
|
1827 * descendants. |
|
1828 * |
|
1829 * Otherwise, if the frame has the NS_FRAME_HAS_DIRTY_CHILDREN bit |
|
1830 * set, then it is responsible for reflowing at least those |
|
1831 * children that have NS_FRAME_HAS_DIRTY_CHILDREN or NS_FRAME_IS_DIRTY |
|
1832 * set. |
|
1833 * |
|
1834 * If a difference in available size from the previous reflow causes |
|
1835 * the frame's size to change, it should reflow descendants as needed. |
|
1836 * |
|
1837 * @param aReflowMetrics <i>out</i> parameter where you should return the |
|
1838 * desired size and ascent/descent info. You should include any |
|
1839 * space you want for border/padding in the desired size you return. |
|
1840 * |
|
1841 * It's okay to return a desired size that exceeds the avail |
|
1842 * size if that's the smallest you can be, i.e. it's your |
|
1843 * minimum size. |
|
1844 * |
|
1845 * For an incremental reflow you are responsible for invalidating |
|
1846 * any area within your frame that needs repainting (including |
|
1847 * borders). If your new desired size is different than your current |
|
1848 * size, then your parent frame is responsible for making sure that |
|
1849 * the difference between the two rects is repainted |
|
1850 * |
|
1851 * @param aReflowState information about your reflow including the reason |
|
1852 * for the reflow and the available space in which to lay out. Each |
|
1853 * dimension of the available space can either be constrained or |
|
1854 * unconstrained (a value of NS_UNCONSTRAINEDSIZE). |
|
1855 * |
|
1856 * Note that the available space can be negative. In this case you |
|
1857 * still must return an accurate desired size. If you're a container |
|
1858 * you must <b>always</b> reflow at least one frame regardless of the |
|
1859 * available space |
|
1860 * |
|
1861 * @param aStatus a return value indicating whether the frame is complete |
|
1862 * and whether the next-in-flow is dirty and needs to be reflowed |
|
1863 */ |
|
1864 virtual nsresult Reflow(nsPresContext* aPresContext, |
|
1865 nsHTMLReflowMetrics& aReflowMetrics, |
|
1866 const nsHTMLReflowState& aReflowState, |
|
1867 nsReflowStatus& aStatus) = 0; |
|
1868 |
|
1869 /** |
|
1870 * Post-reflow hook. After a frame is reflowed this method will be called |
|
1871 * informing the frame that this reflow process is complete, and telling the |
|
1872 * frame the status returned by the Reflow member function. |
|
1873 * |
|
1874 * This call may be invoked many times, while NS_FRAME_IN_REFLOW is set, before |
|
1875 * it is finally called once with a NS_FRAME_REFLOW_COMPLETE value. When called |
|
1876 * with a NS_FRAME_REFLOW_COMPLETE value the NS_FRAME_IN_REFLOW bit in the |
|
1877 * frame state will be cleared. |
|
1878 * |
|
1879 * XXX This doesn't make sense. If the frame is reflowed but not complete, then |
|
1880 * the status should be NS_FRAME_NOT_COMPLETE and not NS_FRAME_COMPLETE |
|
1881 * XXX Don't we want the semantics to dictate that we only call this once for |
|
1882 * a given reflow? |
|
1883 */ |
|
1884 virtual nsresult DidReflow(nsPresContext* aPresContext, |
|
1885 const nsHTMLReflowState* aReflowState, |
|
1886 nsDidReflowStatus aStatus) = 0; |
|
1887 |
|
1888 // XXX Maybe these three should be a separate interface? |
|
1889 |
|
1890 /** |
|
1891 * Updates the overflow areas of the frame. This can be called if an |
|
1892 * overflow area of the frame's children has changed without reflowing. |
|
1893 * @return true if either of the overflow areas for this frame have changed. |
|
1894 */ |
|
1895 virtual bool UpdateOverflow() = 0; |
|
1896 |
|
1897 /** |
|
1898 * Helper method used by block reflow to identify runs of text so |
|
1899 * that proper word-breaking can be done. |
|
1900 * |
|
1901 * @return |
|
1902 * true if we can continue a "text run" through the frame. A |
|
1903 * text run is text that should be treated contiguously for line |
|
1904 * and word breaking. |
|
1905 */ |
|
1906 virtual bool CanContinueTextRun() const = 0; |
|
1907 |
|
1908 /** |
|
1909 * Append the rendered text to the passed-in string. |
|
1910 * The appended text will often not contain all the whitespace from source, |
|
1911 * depending on whether the CSS rule "white-space: pre" is active for this frame. |
|
1912 * if aStartOffset + aLength goes past end, or if aLength is not specified |
|
1913 * then use the text up to the string's end. |
|
1914 * Call this on the primary frame for a text node. |
|
1915 * @param aAppendToString String to append text to, or null if text should not be returned |
|
1916 * @param aSkipChars if aSkipIter is non-null, this must also be non-null. |
|
1917 * This gets used as backing data for the iterator so it should outlive the iterator. |
|
1918 * @param aSkipIter Where to fill in the gfxSkipCharsIterator info, or null if not needed by caller |
|
1919 * @param aStartOffset Skipped (rendered text) start offset |
|
1920 * @param aSkippedMaxLength Maximum number of characters to return |
|
1921 * The iterator can be used to map content offsets to offsets in the returned string, or vice versa. |
|
1922 */ |
|
1923 virtual nsresult GetRenderedText(nsAString* aAppendToString = nullptr, |
|
1924 gfxSkipChars* aSkipChars = nullptr, |
|
1925 gfxSkipCharsIterator* aSkipIter = nullptr, |
|
1926 uint32_t aSkippedStartOffset = 0, |
|
1927 uint32_t aSkippedMaxLength = UINT32_MAX) |
|
1928 { return NS_ERROR_NOT_IMPLEMENTED; } |
|
1929 |
|
1930 /** |
|
1931 * Returns true if the frame contains any non-collapsed characters. |
|
1932 * This method is only available for text frames, and it will return false |
|
1933 * for all other frame types. |
|
1934 */ |
|
1935 virtual bool HasAnyNoncollapsedCharacters() |
|
1936 { return false; } |
|
1937 |
|
1938 /** |
|
1939 * Accessor functions to get/set the associated view object |
|
1940 * |
|
1941 * GetView returns non-null if and only if |HasView| returns true. |
|
1942 */ |
|
1943 bool HasView() const { return !!(mState & NS_FRAME_HAS_VIEW); } |
|
1944 nsView* GetView() const; |
|
1945 virtual nsView* GetViewExternal() const; |
|
1946 nsresult SetView(nsView* aView); |
|
1947 |
|
1948 /** |
|
1949 * Find the closest view (on |this| or an ancestor). |
|
1950 * If aOffset is non-null, it will be set to the offset of |this| |
|
1951 * from the returned view. |
|
1952 */ |
|
1953 nsView* GetClosestView(nsPoint* aOffset = nullptr) const; |
|
1954 |
|
1955 /** |
|
1956 * Find the closest ancestor (excluding |this| !) that has a view |
|
1957 */ |
|
1958 nsIFrame* GetAncestorWithView() const; |
|
1959 virtual nsIFrame* GetAncestorWithViewExternal() const; |
|
1960 |
|
1961 /** |
|
1962 * Get the offset between the coordinate systems of |this| and aOther. |
|
1963 * Adding the return value to a point in the coordinate system of |this| |
|
1964 * will transform the point to the coordinate system of aOther. |
|
1965 * |
|
1966 * aOther must be non-null. |
|
1967 * |
|
1968 * This function is fastest when aOther is an ancestor of |this|. |
|
1969 * |
|
1970 * This function _DOES NOT_ work across document boundaries. |
|
1971 * Use this function only when |this| and aOther are in the same document. |
|
1972 * |
|
1973 * NOTE: this actually returns the offset from aOther to |this|, but |
|
1974 * that offset is added to transform _coordinates_ from |this| to |
|
1975 * aOther. |
|
1976 */ |
|
1977 nsPoint GetOffsetTo(const nsIFrame* aOther) const; |
|
1978 virtual nsPoint GetOffsetToExternal(const nsIFrame* aOther) const; |
|
1979 |
|
1980 /** |
|
1981 * Get the offset between the coordinate systems of |this| and aOther |
|
1982 * expressed in appunits per dev pixel of |this|' document. Adding the return |
|
1983 * value to a point that is relative to the origin of |this| will make the |
|
1984 * point relative to the origin of aOther but in the appunits per dev pixel |
|
1985 * ratio of |this|. |
|
1986 * |
|
1987 * aOther must be non-null. |
|
1988 * |
|
1989 * This function is fastest when aOther is an ancestor of |this|. |
|
1990 * |
|
1991 * This function works across document boundaries. |
|
1992 * |
|
1993 * Because this function may cross document boundaries that have different |
|
1994 * app units per dev pixel ratios it needs to be used very carefully. |
|
1995 * |
|
1996 * NOTE: this actually returns the offset from aOther to |this|, but |
|
1997 * that offset is added to transform _coordinates_ from |this| to |
|
1998 * aOther. |
|
1999 */ |
|
2000 nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther) const; |
|
2001 |
|
2002 /** |
|
2003 * Get the screen rect of the frame in pixels. |
|
2004 * @return the pixel rect of the frame in screen coordinates. |
|
2005 */ |
|
2006 nsIntRect GetScreenRect() const; |
|
2007 virtual nsIntRect GetScreenRectExternal() const; |
|
2008 |
|
2009 /** |
|
2010 * Get the screen rect of the frame in app units. |
|
2011 * @return the app unit rect of the frame in screen coordinates. |
|
2012 */ |
|
2013 nsRect GetScreenRectInAppUnits() const; |
|
2014 virtual nsRect GetScreenRectInAppUnitsExternal() const; |
|
2015 |
|
2016 /** |
|
2017 * Returns the offset from this frame to the closest geometric parent that |
|
2018 * has a view. Also returns the containing view or null in case of error |
|
2019 */ |
|
2020 void GetOffsetFromView(nsPoint& aOffset, nsView** aView) const; |
|
2021 |
|
2022 /** |
|
2023 * Returns the nearest widget containing this frame. If this frame has a |
|
2024 * view and the view has a widget, then this frame's widget is |
|
2025 * returned, otherwise this frame's geometric parent is checked |
|
2026 * recursively upwards. |
|
2027 * XXX virtual because gfx callers use it! (themes) |
|
2028 */ |
|
2029 virtual nsIWidget* GetNearestWidget() const; |
|
2030 |
|
2031 /** |
|
2032 * Same as GetNearestWidget() above but uses an outparam to return the offset |
|
2033 * of this frame to the returned widget expressed in appunits of |this| (the |
|
2034 * widget might be in a different document with a different zoom). |
|
2035 */ |
|
2036 virtual nsIWidget* GetNearestWidget(nsPoint& aOffset) const; |
|
2037 |
|
2038 /** |
|
2039 * Get the "type" of the frame. May return nullptr. |
|
2040 * |
|
2041 * @see nsGkAtoms |
|
2042 */ |
|
2043 virtual nsIAtom* GetType() const = 0; |
|
2044 |
|
2045 /** |
|
2046 * Returns a transformation matrix that converts points in this frame's |
|
2047 * coordinate space to points in some ancestor frame's coordinate space. |
|
2048 * The frame decides which ancestor it will use as a reference point. |
|
2049 * If this frame has no ancestor, aOutAncestor will be set to null. |
|
2050 * |
|
2051 * @param aStopAtAncestor don't look further than aStopAtAncestor. If null, |
|
2052 * all ancestors (including across documents) will be traversed. |
|
2053 * @param aOutAncestor [out] The ancestor frame the frame has chosen. If |
|
2054 * this frame has no ancestor, *aOutAncestor will be set to null. If |
|
2055 * this frame is not a root frame, then *aOutAncestor will be in the same |
|
2056 * document as this frame. If this frame IsTransformed(), then *aOutAncestor |
|
2057 * will be the parent frame (if not preserve-3d) or the nearest non-transformed |
|
2058 * ancestor (if preserve-3d). |
|
2059 * @return A gfxMatrix that converts points in this frame's coordinate space |
|
2060 * into points in aOutAncestor's coordinate space. |
|
2061 */ |
|
2062 gfx3DMatrix GetTransformMatrix(const nsIFrame* aStopAtAncestor, |
|
2063 nsIFrame **aOutAncestor); |
|
2064 |
|
2065 /** |
|
2066 * Bit-flags to pass to IsFrameOfType() |
|
2067 */ |
|
2068 enum { |
|
2069 eMathML = 1 << 0, |
|
2070 eSVG = 1 << 1, |
|
2071 eSVGForeignObject = 1 << 2, |
|
2072 eSVGContainer = 1 << 3, |
|
2073 eSVGGeometry = 1 << 4, |
|
2074 eSVGPaintServer = 1 << 5, |
|
2075 eBidiInlineContainer = 1 << 6, |
|
2076 // the frame is for a replaced element, such as an image |
|
2077 eReplaced = 1 << 7, |
|
2078 // Frame that contains a block but looks like a replaced element |
|
2079 // from the outside |
|
2080 eReplacedContainsBlock = 1 << 8, |
|
2081 // A frame that participates in inline reflow, i.e., one that |
|
2082 // requires nsHTMLReflowState::mLineLayout. |
|
2083 eLineParticipant = 1 << 9, |
|
2084 eXULBox = 1 << 10, |
|
2085 eCanContainOverflowContainers = 1 << 11, |
|
2086 eBlockFrame = 1 << 12, |
|
2087 eTablePart = 1 << 13, |
|
2088 // If this bit is set, the frame doesn't allow ignorable whitespace as |
|
2089 // children. For example, the whitespace between <table>\n<tr>\n<td> |
|
2090 // will be excluded during the construction of children. |
|
2091 eExcludesIgnorableWhitespace = 1 << 14, |
|
2092 eSupportsCSSTransforms = 1 << 15, |
|
2093 |
|
2094 // These are to allow nsFrame::Init to assert that IsFrameOfType |
|
2095 // implementations all call the base class method. They are only |
|
2096 // meaningful in DEBUG builds. |
|
2097 eDEBUGAllFrames = 1 << 30, |
|
2098 eDEBUGNoFrames = 1 << 31 |
|
2099 }; |
|
2100 |
|
2101 /** |
|
2102 * API for doing a quick check if a frame is of a given |
|
2103 * type. Returns true if the frame matches ALL flags passed in. |
|
2104 * |
|
2105 * Implementations should always override with inline virtual |
|
2106 * functions that call the base class's IsFrameOfType method. |
|
2107 */ |
|
2108 virtual bool IsFrameOfType(uint32_t aFlags) const |
|
2109 { |
|
2110 #ifdef DEBUG |
|
2111 return !(aFlags & ~(nsIFrame::eDEBUGAllFrames | nsIFrame::eSupportsCSSTransforms)); |
|
2112 #else |
|
2113 return !(aFlags & ~nsIFrame::eSupportsCSSTransforms); |
|
2114 #endif |
|
2115 } |
|
2116 |
|
2117 /** |
|
2118 * Returns true if the frame is a block wrapper. |
|
2119 */ |
|
2120 bool IsBlockWrapper() const; |
|
2121 |
|
2122 /** |
|
2123 * Get this frame's CSS containing block. |
|
2124 * |
|
2125 * The algorithm is defined in |
|
2126 * http://www.w3.org/TR/CSS2/visudet.html#containing-block-details. |
|
2127 * |
|
2128 * NOTE: This is guaranteed to return a non-null pointer when invoked on any |
|
2129 * frame other than the root frame. |
|
2130 */ |
|
2131 nsIFrame* GetContainingBlock() const; |
|
2132 |
|
2133 /** |
|
2134 * Is this frame a containing block for floating elements? |
|
2135 * Note that very few frames are, so default to false. |
|
2136 */ |
|
2137 virtual bool IsFloatContainingBlock() const { return false; } |
|
2138 |
|
2139 /** |
|
2140 * Is this a leaf frame? Frames that want the frame constructor to be able |
|
2141 * to construct kids for them should return false, all others should return |
|
2142 * true. Note that returning true here does not mean that the frame _can't_ |
|
2143 * have kids. It could still have kids created via |
|
2144 * nsIAnonymousContentCreator. Returning true indicates that "normal" |
|
2145 * (non-anonymous, XBL-bound, CSS generated content, etc) children should not |
|
2146 * be constructed. |
|
2147 */ |
|
2148 virtual bool IsLeaf() const; |
|
2149 |
|
2150 /** |
|
2151 * Marks all display items created by this frame as needing a repaint, |
|
2152 * and calls SchedulePaint() if requested and one is not already pending. |
|
2153 * |
|
2154 * This includes all display items created by this frame, including |
|
2155 * container types. |
|
2156 * |
|
2157 * @param aDisplayItemKey If specified, only issues an invalidate |
|
2158 * if this frame painted a display item of that type during the |
|
2159 * previous paint. SVG rendering observers are always notified. |
|
2160 */ |
|
2161 virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0); |
|
2162 |
|
2163 /** |
|
2164 * Same as InvalidateFrame(), but only mark a fixed rect as needing |
|
2165 * repainting. |
|
2166 * |
|
2167 * @param aRect The rect to invalidate, relative to the TopLeft of the |
|
2168 * frame's border box. |
|
2169 * @param aDisplayItemKey If specified, only issues an invalidate |
|
2170 * if this frame painted a display item of that type during the |
|
2171 * previous paint. SVG rendering observers are always notified. |
|
2172 */ |
|
2173 virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0); |
|
2174 |
|
2175 /** |
|
2176 * Calls InvalidateFrame() on all frames descendant frames (including |
|
2177 * this one). |
|
2178 * |
|
2179 * This function doesn't walk through placeholder frames to invalidate |
|
2180 * the out-of-flow frames. |
|
2181 * |
|
2182 * @param aDisplayItemKey If specified, only issues an invalidate |
|
2183 * if this frame painted a display item of that type during the |
|
2184 * previous paint. SVG rendering observers are always notified. |
|
2185 */ |
|
2186 void InvalidateFrameSubtree(uint32_t aDisplayItemKey = 0); |
|
2187 |
|
2188 /** |
|
2189 * Called when a frame is about to be removed and needs to be invalidated. |
|
2190 * Normally does nothing since DLBI handles removed frames. |
|
2191 */ |
|
2192 virtual void InvalidateFrameForRemoval() {} |
|
2193 |
|
2194 /** |
|
2195 * When HasUserData(frame->LayerIsPrerenderedDataKey()), then the |
|
2196 * entire overflow area of this frame has been rendered in its |
|
2197 * layer(s). |
|
2198 */ |
|
2199 static void* LayerIsPrerenderedDataKey() { |
|
2200 return &sLayerIsPrerenderedDataKey; |
|
2201 } |
|
2202 static uint8_t sLayerIsPrerenderedDataKey; |
|
2203 |
|
2204 /** |
|
2205 * Try to update this frame's transform without invalidating any |
|
2206 * content. Return true iff successful. If unsuccessful, the |
|
2207 * caller is responsible for scheduling an invalidating paint. |
|
2208 * |
|
2209 * If the result is true, aLayerResult will be filled in with the |
|
2210 * transform layer for the frame. |
|
2211 */ |
|
2212 bool TryUpdateTransformOnly(Layer** aLayerResult); |
|
2213 |
|
2214 /** |
|
2215 * Checks if a frame has had InvalidateFrame() called on it since the |
|
2216 * last paint. |
|
2217 * |
|
2218 * If true, then the invalid rect is returned in aRect, with an |
|
2219 * empty rect meaning all pixels drawn by this frame should be |
|
2220 * invalidated. |
|
2221 * If false, aRect is left unchanged. |
|
2222 */ |
|
2223 bool IsInvalid(nsRect& aRect); |
|
2224 |
|
2225 /** |
|
2226 * Check if any frame within the frame subtree (including this frame) |
|
2227 * returns true for IsInvalid(). |
|
2228 */ |
|
2229 bool HasInvalidFrameInSubtree() |
|
2230 { |
|
2231 return HasAnyStateBits(NS_FRAME_NEEDS_PAINT | NS_FRAME_DESCENDANT_NEEDS_PAINT); |
|
2232 } |
|
2233 |
|
2234 /** |
|
2235 * Removes the invalid state from the current frame and all |
|
2236 * descendant frames. |
|
2237 */ |
|
2238 void ClearInvalidationStateBits(); |
|
2239 |
|
2240 /** |
|
2241 * Ensures that the refresh driver is running, and schedules a view |
|
2242 * manager flush on the next tick. |
|
2243 * |
|
2244 * The view manager flush will update the layer tree, repaint any |
|
2245 * invalid areas in the layer tree and schedule a layer tree |
|
2246 * composite operation to display the layer tree. |
|
2247 * |
|
2248 * In general it is not necessary for frames to call this when they change. |
|
2249 * For example, changes that result in a reflow will have this called for |
|
2250 * them by PresContext::DoReflow when the reflow begins. Style changes that |
|
2251 * do not trigger a reflow should have this called for them by |
|
2252 * DoApplyRenderingChangeToTree. |
|
2253 * |
|
2254 * @param aType PAINT_COMPOSITE_ONLY : No changes have been made |
|
2255 * that require a layer tree update, so only schedule a layer |
|
2256 * tree composite. |
|
2257 * PAINT_DELAYED_COMPRESS : Schedule a paint to be executed after a delay, and |
|
2258 * put FrameLayerBuilder in 'compressed' mode that avoids short cut optimizations. |
|
2259 */ |
|
2260 enum PaintType { |
|
2261 PAINT_DEFAULT = 0, |
|
2262 PAINT_COMPOSITE_ONLY, |
|
2263 PAINT_DELAYED_COMPRESS |
|
2264 }; |
|
2265 void SchedulePaint(PaintType aType = PAINT_DEFAULT); |
|
2266 |
|
2267 /** |
|
2268 * Checks if the layer tree includes a dedicated layer for this |
|
2269 * frame/display item key pair, and invalidates at least aDamageRect |
|
2270 * area within that layer. |
|
2271 * |
|
2272 * If no layer is found, calls InvalidateFrame() instead. |
|
2273 * |
|
2274 * @param aDamageRect Area of the layer to invalidate. |
|
2275 * @param aDisplayItemKey Display item type. |
|
2276 * @param aFlags UPDATE_IS_ASYNC : Will skip the invalidation |
|
2277 * if the found layer is being composited by a remote |
|
2278 * compositor. |
|
2279 * @return Layer, if found, nullptr otherwise. |
|
2280 */ |
|
2281 enum { |
|
2282 UPDATE_IS_ASYNC = 1 << 0 |
|
2283 }; |
|
2284 Layer* InvalidateLayer(uint32_t aDisplayItemKey, const nsIntRect* aDamageRect = nullptr, uint32_t aFlags = 0); |
|
2285 |
|
2286 /** |
|
2287 * Returns a rect that encompasses everything that might be painted by |
|
2288 * this frame. This includes this frame, all its descendent frames, this |
|
2289 * frame's outline, and descentant frames' outline, but does not include |
|
2290 * areas clipped out by the CSS "overflow" and "clip" properties. |
|
2291 * |
|
2292 * HasOverflowRects() (below) will return true when this overflow |
|
2293 * rect has been explicitly set, even if it matches mRect. |
|
2294 * XXX Note: because of a space optimization using the formula above, |
|
2295 * during reflow this function does not give accurate data if |
|
2296 * FinishAndStoreOverflow has been called but mRect hasn't yet been |
|
2297 * updated yet. FIXME: This actually isn't true, but it should be. |
|
2298 * |
|
2299 * The visual overflow rect should NEVER be used for things that |
|
2300 * affect layout. The scrollable overflow rect is permitted to affect |
|
2301 * layout. |
|
2302 * |
|
2303 * @return the rect relative to this frame's origin, but after |
|
2304 * CSS transforms have been applied (i.e. not really this frame's coordinate |
|
2305 * system, and may not contain the frame's border-box, e.g. if there |
|
2306 * is a CSS transform scaling it down) |
|
2307 */ |
|
2308 nsRect GetVisualOverflowRect() const { |
|
2309 return GetOverflowRect(eVisualOverflow); |
|
2310 } |
|
2311 |
|
2312 /** |
|
2313 * Returns a rect that encompasses the area of this frame that the |
|
2314 * user should be able to scroll to reach. This is similar to |
|
2315 * GetVisualOverflowRect, but does not include outline or shadows, and |
|
2316 * may in the future include more margins than visual overflow does. |
|
2317 * It does not include areas clipped out by the CSS "overflow" and |
|
2318 * "clip" properties. |
|
2319 * |
|
2320 * HasOverflowRects() (below) will return true when this overflow |
|
2321 * rect has been explicitly set, even if it matches mRect. |
|
2322 * XXX Note: because of a space optimization using the formula above, |
|
2323 * during reflow this function does not give accurate data if |
|
2324 * FinishAndStoreOverflow has been called but mRect hasn't yet been |
|
2325 * updated yet. |
|
2326 * |
|
2327 * @return the rect relative to this frame's origin, but after |
|
2328 * CSS transforms have been applied (i.e. not really this frame's coordinate |
|
2329 * system, and may not contain the frame's border-box, e.g. if there |
|
2330 * is a CSS transform scaling it down) |
|
2331 */ |
|
2332 nsRect GetScrollableOverflowRect() const { |
|
2333 return GetOverflowRect(eScrollableOverflow); |
|
2334 } |
|
2335 |
|
2336 nsRect GetOverflowRect(nsOverflowType aType) const; |
|
2337 |
|
2338 nsOverflowAreas GetOverflowAreas() const; |
|
2339 |
|
2340 /** |
|
2341 * Same as GetOverflowAreas, except in this frame's coordinate |
|
2342 * system (before transforms are applied). |
|
2343 * |
|
2344 * @return the overflow areas relative to this frame, before any CSS transforms have |
|
2345 * been applied, i.e. in this frame's coordinate system |
|
2346 */ |
|
2347 nsOverflowAreas GetOverflowAreasRelativeToSelf() const; |
|
2348 |
|
2349 /** |
|
2350 * Same as GetScrollableOverflowRect, except relative to the parent |
|
2351 * frame. |
|
2352 * |
|
2353 * @return the rect relative to the parent frame, in the parent frame's |
|
2354 * coordinate system |
|
2355 */ |
|
2356 nsRect GetScrollableOverflowRectRelativeToParent() const; |
|
2357 |
|
2358 /** |
|
2359 * Same as GetScrollableOverflowRect, except in this frame's coordinate |
|
2360 * system (before transforms are applied). |
|
2361 * |
|
2362 * @return the rect relative to this frame, before any CSS transforms have |
|
2363 * been applied, i.e. in this frame's coordinate system |
|
2364 */ |
|
2365 nsRect GetScrollableOverflowRectRelativeToSelf() const; |
|
2366 |
|
2367 /** |
|
2368 * Like GetVisualOverflowRect, except in this frame's |
|
2369 * coordinate system (before transforms are applied). |
|
2370 * |
|
2371 * @return the rect relative to this frame, before any CSS transforms have |
|
2372 * been applied, i.e. in this frame's coordinate system |
|
2373 */ |
|
2374 nsRect GetVisualOverflowRectRelativeToSelf() const; |
|
2375 |
|
2376 /** |
|
2377 * Returns this frame's visual overflow rect as it would be before taking |
|
2378 * account of SVG effects or transforms. The rect returned is relative to |
|
2379 * this frame. |
|
2380 */ |
|
2381 nsRect GetPreEffectsVisualOverflowRect() const; |
|
2382 |
|
2383 /** |
|
2384 * Store the overflow area in the frame's mOverflow.mVisualDeltas |
|
2385 * fields or as a frame property in the frame manager so that it can |
|
2386 * be retrieved later without reflowing the frame. Returns true if either of |
|
2387 * the overflow areas changed. |
|
2388 */ |
|
2389 bool FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas, |
|
2390 nsSize aNewSize, nsSize* aOldSize = nullptr); |
|
2391 |
|
2392 bool FinishAndStoreOverflow(nsHTMLReflowMetrics* aMetrics) { |
|
2393 return FinishAndStoreOverflow(aMetrics->mOverflowAreas, |
|
2394 nsSize(aMetrics->Width(), aMetrics->Height())); |
|
2395 } |
|
2396 |
|
2397 /** |
|
2398 * Returns whether the frame has an overflow rect that is different from |
|
2399 * its border-box. |
|
2400 */ |
|
2401 bool HasOverflowAreas() const { |
|
2402 return mOverflow.mType != NS_FRAME_OVERFLOW_NONE; |
|
2403 } |
|
2404 |
|
2405 /** |
|
2406 * Removes any stored overflow rects (visual and scrollable) from the frame. |
|
2407 * Returns true if the overflow changed. |
|
2408 */ |
|
2409 bool ClearOverflowRects(); |
|
2410 |
|
2411 /** |
|
2412 * Determine whether borders should not be painted on certain sides of the |
|
2413 * frame. |
|
2414 * |
|
2415 * @note (See also bug 743402, comment 11) GetSkipSides() and its sister |
|
2416 * method, ApplySkipSides() checks to see if this frame has a previous |
|
2417 * or next continuation to determine if a side should be skipped. |
|
2418 * Unfortunately, this only works after reflow has been completed. In |
|
2419 * lieu of this, during reflow, an nsHTMLReflowState parameter can be |
|
2420 * passed in, indicating that it should be used to determine if sides |
|
2421 * should be skipped during reflow. |
|
2422 */ |
|
2423 #define LOGICAL_SIDE_B_START 1 |
|
2424 #define LOGICAL_SIDE_I_START 2 |
|
2425 #define LOGICAL_SIDE_B_END 4 |
|
2426 #define LOGICAL_SIDE_I_END 8 |
|
2427 #define LOGICAL_SIDES_I_BOTH (LOGICAL_SIDE_I_START | LOGICAL_SIDE_I_END) |
|
2428 #define LOGICAL_SIDES_B_BOTH (LOGICAL_SIDE_B_START | LOGICAL_SIDE_B_END) |
|
2429 #define LOGICAL_SIDES_ALL (LOGICAL_SIDE_I_START | LOGICAL_SIDE_I_END | \ |
|
2430 LOGICAL_SIDE_B_START | LOGICAL_SIDE_B_END) |
|
2431 int GetSkipSides(const nsHTMLReflowState* aReflowState = nullptr) const; |
|
2432 virtual int |
|
2433 GetLogicalSkipSides(const nsHTMLReflowState* aReflowState = nullptr) const { |
|
2434 return 0; |
|
2435 } |
|
2436 |
|
2437 /** |
|
2438 * @returns true if this frame is selected. |
|
2439 */ |
|
2440 bool IsSelected() const; |
|
2441 |
|
2442 /** |
|
2443 * called to discover where this frame, or a parent frame has user-select style |
|
2444 * applied, which affects that way that it is selected. |
|
2445 * |
|
2446 * @param aIsSelectable out param. Set to true if the frame can be selected |
|
2447 * (i.e. is not affected by user-select: none) |
|
2448 * @param aSelectStyle out param. Returns the type of selection style found |
|
2449 * (using values defined in nsStyleConsts.h). |
|
2450 */ |
|
2451 virtual nsresult IsSelectable(bool* aIsSelectable, uint8_t* aSelectStyle) const = 0; |
|
2452 |
|
2453 /** |
|
2454 * Called to retrieve the SelectionController associated with the frame. |
|
2455 * @param aSelCon will contain the selection controller associated with |
|
2456 * the frame. |
|
2457 */ |
|
2458 virtual nsresult GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon) = 0; |
|
2459 |
|
2460 /** |
|
2461 * Call to get nsFrameSelection for this frame. |
|
2462 */ |
|
2463 already_AddRefed<nsFrameSelection> GetFrameSelection(); |
|
2464 |
|
2465 /** |
|
2466 * GetConstFrameSelection returns an object which methods are safe to use for |
|
2467 * example in nsIFrame code. |
|
2468 */ |
|
2469 const nsFrameSelection* GetConstFrameSelection() const; |
|
2470 |
|
2471 /** |
|
2472 * called to find the previous/next character, word, or line returns the actual |
|
2473 * nsIFrame and the frame offset. THIS DOES NOT CHANGE SELECTION STATE |
|
2474 * uses frame's begin selection state to start. if no selection on this frame will |
|
2475 * return NS_ERROR_FAILURE |
|
2476 * @param aPOS is defined in nsFrameSelection |
|
2477 */ |
|
2478 virtual nsresult PeekOffset(nsPeekOffsetStruct *aPos); |
|
2479 |
|
2480 /** |
|
2481 * called to find the previous/next selectable leaf frame. |
|
2482 * @param aDirection [in] the direction to move in (eDirPrevious or eDirNext) |
|
2483 * @param aVisual [in] whether bidi caret behavior is visual (true) or logical (false) |
|
2484 * @param aJumpLines [in] whether to allow jumping across line boundaries |
|
2485 * @param aScrollViewStop [in] whether to stop when reaching a scroll frame boundary |
|
2486 * @param aOutFrame [out] the previous/next selectable leaf frame |
|
2487 * @param aOutOffset [out] 0 indicates that we arrived at the beginning of the output frame; |
|
2488 * -1 indicates that we arrived at its end. |
|
2489 * @param aOutJumpedLine [out] whether this frame and the returned frame are on different lines |
|
2490 */ |
|
2491 nsresult GetFrameFromDirection(nsDirection aDirection, bool aVisual, |
|
2492 bool aJumpLines, bool aScrollViewStop, |
|
2493 nsIFrame** aOutFrame, int32_t* aOutOffset, bool* aOutJumpedLine); |
|
2494 |
|
2495 /** |
|
2496 * called to see if the children of the frame are visible from indexstart to index end. |
|
2497 * this does not change any state. returns true only if the indexes are valid and any of |
|
2498 * the children are visible. for textframes this index is the character index. |
|
2499 * if aStart = aEnd result will be false |
|
2500 * @param aStart start index of first child from 0-N (number of children) |
|
2501 * @param aEnd end index of last child from 0-N |
|
2502 * @param aRecurse should this frame talk to siblings to get to the contents other children? |
|
2503 * @param aFinished did this frame have the aEndIndex? or is there more work to do |
|
2504 * @param _retval return value true or false. false = range is not rendered. |
|
2505 */ |
|
2506 virtual nsresult CheckVisibility(nsPresContext* aContext, int32_t aStartIndex, int32_t aEndIndex, bool aRecurse, bool *aFinished, bool *_retval)=0; |
|
2507 |
|
2508 /** |
|
2509 * Called to tell a frame that one of its child frames is dirty (i.e., |
|
2510 * has the NS_FRAME_IS_DIRTY *or* NS_FRAME_HAS_DIRTY_CHILDREN bit |
|
2511 * set). This should always set the NS_FRAME_HAS_DIRTY_CHILDREN on |
|
2512 * the frame, and may do other work. |
|
2513 */ |
|
2514 virtual void ChildIsDirty(nsIFrame* aChild) = 0; |
|
2515 |
|
2516 /** |
|
2517 * Called to retrieve this frame's accessible. |
|
2518 * If this frame implements Accessibility return a valid accessible |
|
2519 * If not return NS_ERROR_NOT_IMPLEMENTED. |
|
2520 * Note: Accessible must be refcountable. Do not implement directly on your frame |
|
2521 * Use a mediatior of some kind. |
|
2522 */ |
|
2523 #ifdef ACCESSIBILITY |
|
2524 virtual mozilla::a11y::AccType AccessibleType() = 0; |
|
2525 #endif |
|
2526 |
|
2527 /** |
|
2528 * Get the frame whose style context should be the parent of this |
|
2529 * frame's style context (i.e., provide the parent style context). |
|
2530 * This frame must either be an ancestor of this frame or a child. If |
|
2531 * this returns a child frame, then the child frame must be sure to |
|
2532 * return a grandparent or higher! Furthermore, if a child frame is |
|
2533 * returned it must have the same GetContent() as this frame. |
|
2534 * |
|
2535 * @return The frame whose style context should be the parent of this frame's |
|
2536 * style context. Null is permitted, and means that this frame's |
|
2537 * style context should be the root of the style context tree. |
|
2538 */ |
|
2539 virtual nsIFrame* GetParentStyleContextFrame() const = 0; |
|
2540 |
|
2541 /** |
|
2542 * Determines whether a frame is visible for painting; |
|
2543 * taking into account whether it is painting a selection or printing. |
|
2544 */ |
|
2545 bool IsVisibleForPainting(nsDisplayListBuilder* aBuilder); |
|
2546 /** |
|
2547 * Determines whether a frame is visible for painting or collapsed; |
|
2548 * taking into account whether it is painting a selection or printing, |
|
2549 */ |
|
2550 bool IsVisibleOrCollapsedForPainting(nsDisplayListBuilder* aBuilder); |
|
2551 /** |
|
2552 * As above, but slower because we have to recompute some stuff that |
|
2553 * aBuilder already has. |
|
2554 */ |
|
2555 bool IsVisibleForPainting(); |
|
2556 /** |
|
2557 * Check whether this frame is visible in the current selection. Returns |
|
2558 * true if there is no current selection. |
|
2559 */ |
|
2560 bool IsVisibleInSelection(nsDisplayListBuilder* aBuilder); |
|
2561 |
|
2562 /** |
|
2563 * Overridable function to determine whether this frame should be considered |
|
2564 * "in" the given non-null aSelection for visibility purposes. |
|
2565 */ |
|
2566 virtual bool IsVisibleInSelection(nsISelection* aSelection); |
|
2567 |
|
2568 /** |
|
2569 * Determines whether this frame is a pseudo stacking context, looking |
|
2570 * only as style --- i.e., assuming that it's in-flow and not a replaced |
|
2571 * element and not an SVG element. |
|
2572 * XXX maybe check IsTransformed()? |
|
2573 */ |
|
2574 bool IsPseudoStackingContextFromStyle(); |
|
2575 |
|
2576 virtual bool HonorPrintBackgroundSettings() { return true; } |
|
2577 |
|
2578 /** |
|
2579 * Determine whether the frame is logically empty, which is roughly |
|
2580 * whether the layout would be the same whether or not the frame is |
|
2581 * present. Placeholder frames should return true. Block frames |
|
2582 * should be considered empty whenever margins collapse through them, |
|
2583 * even though those margins are relevant. Text frames containing |
|
2584 * only whitespace that does not contribute to the height of the line |
|
2585 * should return true. |
|
2586 */ |
|
2587 virtual bool IsEmpty() = 0; |
|
2588 /** |
|
2589 * Return the same as IsEmpty(). This may only be called after the frame |
|
2590 * has been reflowed and before any further style or content changes. |
|
2591 */ |
|
2592 virtual bool CachedIsEmpty(); |
|
2593 /** |
|
2594 * Determine whether the frame is logically empty, assuming that all |
|
2595 * its children are empty. |
|
2596 */ |
|
2597 virtual bool IsSelfEmpty() = 0; |
|
2598 |
|
2599 /** |
|
2600 * IsGeneratedContentFrame returns whether a frame corresponds to |
|
2601 * generated content |
|
2602 * |
|
2603 * @return whether the frame correspods to generated content |
|
2604 */ |
|
2605 bool IsGeneratedContentFrame() { |
|
2606 return (mState & NS_FRAME_GENERATED_CONTENT) != 0; |
|
2607 } |
|
2608 |
|
2609 /** |
|
2610 * IsPseudoFrame returns whether a frame is a pseudo frame (eg an |
|
2611 * anonymous table-row frame created for a CSS table-cell without an |
|
2612 * enclosing table-row. |
|
2613 * |
|
2614 * @param aParentContent the content node corresponding to the parent frame |
|
2615 * @return whether the frame is a pseudo frame |
|
2616 */ |
|
2617 bool IsPseudoFrame(nsIContent* aParentContent) { |
|
2618 return mContent == aParentContent; |
|
2619 } |
|
2620 |
|
2621 FrameProperties Properties() const { |
|
2622 return FrameProperties(PresContext()->PropertyTable(), this); |
|
2623 } |
|
2624 |
|
2625 NS_DECLARE_FRAME_PROPERTY(BaseLevelProperty, nullptr) |
|
2626 NS_DECLARE_FRAME_PROPERTY(EmbeddingLevelProperty, nullptr) |
|
2627 NS_DECLARE_FRAME_PROPERTY(ParagraphDepthProperty, nullptr) |
|
2628 |
|
2629 #define NS_GET_BASE_LEVEL(frame) \ |
|
2630 NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::BaseLevelProperty())) |
|
2631 |
|
2632 #define NS_GET_EMBEDDING_LEVEL(frame) \ |
|
2633 NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::EmbeddingLevelProperty())) |
|
2634 |
|
2635 #define NS_GET_PARAGRAPH_DEPTH(frame) \ |
|
2636 NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::ParagraphDepthProperty())) |
|
2637 |
|
2638 /** |
|
2639 * Return true if and only if this frame obeys visibility:hidden. |
|
2640 * if it does not, then nsContainerFrame will hide its view even though |
|
2641 * this means children can't be made visible again. |
|
2642 */ |
|
2643 virtual bool SupportsVisibilityHidden() { return true; } |
|
2644 |
|
2645 /** |
|
2646 * Returns true if the frame has a valid clip rect set via the 'clip' |
|
2647 * property, and the 'clip' property applies to this frame. The 'clip' |
|
2648 * property applies to HTML frames if they are absolutely positioned. The |
|
2649 * 'clip' property applies to SVG frames regardless of the value of the |
|
2650 * 'position' property. |
|
2651 * |
|
2652 * If this method returns true, then we also set aRect to the computed clip |
|
2653 * rect, with coordinates relative to this frame's origin. aRect must not be |
|
2654 * null! |
|
2655 */ |
|
2656 bool GetClipPropClipRect(const nsStyleDisplay* aDisp, nsRect* aRect, |
|
2657 const nsSize& aSize) const; |
|
2658 |
|
2659 /** |
|
2660 * Check if this frame is focusable and in the current tab order. |
|
2661 * Tabbable is indicated by a nonnegative tabindex & is a subset of focusable. |
|
2662 * For example, only the selected radio button in a group is in the |
|
2663 * tab order, unless the radio group has no selection in which case |
|
2664 * all of the visible, non-disabled radio buttons in the group are |
|
2665 * in the tab order. On the other hand, all of the visible, non-disabled |
|
2666 * radio buttons are always focusable via clicking or script. |
|
2667 * Also, depending on the pref accessibility.tabfocus some widgets may be |
|
2668 * focusable but removed from the tab order. This is the default on |
|
2669 * Mac OS X, where fewer items are focusable. |
|
2670 * @param [in, optional] aTabIndex the computed tab index |
|
2671 * < 0 if not tabbable |
|
2672 * == 0 if in normal tab order |
|
2673 * > 0 can be tabbed to in the order specified by this value |
|
2674 * @param [in, optional] aWithMouse, is this focus query for mouse clicking |
|
2675 * @return whether the frame is focusable via mouse, kbd or script. |
|
2676 */ |
|
2677 virtual bool IsFocusable(int32_t *aTabIndex = nullptr, bool aWithMouse = false); |
|
2678 |
|
2679 // BOX LAYOUT METHODS |
|
2680 // These methods have been migrated from nsIBox and are in the process of |
|
2681 // being refactored. DO NOT USE OUTSIDE OF XUL. |
|
2682 bool IsBoxFrame() const |
|
2683 { |
|
2684 return IsFrameOfType(nsIFrame::eXULBox); |
|
2685 } |
|
2686 bool IsBoxWrapped() const |
|
2687 { return (!IsBoxFrame() && mParent && mParent->IsBoxFrame()); } |
|
2688 |
|
2689 enum Halignment { |
|
2690 hAlign_Left, |
|
2691 hAlign_Right, |
|
2692 hAlign_Center |
|
2693 }; |
|
2694 |
|
2695 enum Valignment { |
|
2696 vAlign_Top, |
|
2697 vAlign_Middle, |
|
2698 vAlign_BaseLine, |
|
2699 vAlign_Bottom |
|
2700 }; |
|
2701 |
|
2702 /** |
|
2703 * This calculates the minimum size required for a box based on its state |
|
2704 * @param[in] aBoxLayoutState The desired state to calculate for |
|
2705 * @return The minimum size |
|
2706 */ |
|
2707 virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) = 0; |
|
2708 |
|
2709 /** |
|
2710 * This calculates the preferred size of a box based on its state |
|
2711 * @param[in] aBoxLayoutState The desired state to calculate for |
|
2712 * @return The preferred size |
|
2713 */ |
|
2714 virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState) = 0; |
|
2715 |
|
2716 /** |
|
2717 * This calculates the maximum size for a box based on its state |
|
2718 * @param[in] aBoxLayoutState The desired state to calculate for |
|
2719 * @return The maximum size |
|
2720 */ |
|
2721 virtual nsSize GetMaxSize(nsBoxLayoutState& aBoxLayoutState) = 0; |
|
2722 |
|
2723 /** |
|
2724 * This returns the minimum size for the scroll area if this frame is |
|
2725 * being scrolled. Usually it's (0,0). |
|
2726 */ |
|
2727 virtual nsSize GetMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState) = 0; |
|
2728 |
|
2729 // Implemented in nsBox, used in nsBoxFrame |
|
2730 uint32_t GetOrdinal(); |
|
2731 |
|
2732 virtual nscoord GetFlex(nsBoxLayoutState& aBoxLayoutState) = 0; |
|
2733 virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState) = 0; |
|
2734 virtual bool IsCollapsed() = 0; |
|
2735 // This does not alter the overflow area. If the caller is changing |
|
2736 // the box size, the caller is responsible for updating the overflow |
|
2737 // area. It's enough to just call Layout or SyncLayout on the |
|
2738 // box. You can pass true to aRemoveOverflowArea as a |
|
2739 // convenience. |
|
2740 virtual void SetBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect, |
|
2741 bool aRemoveOverflowAreas = false) = 0; |
|
2742 NS_HIDDEN_(nsresult) Layout(nsBoxLayoutState& aBoxLayoutState); |
|
2743 nsIFrame* GetChildBox() const |
|
2744 { |
|
2745 // box layout ends at box-wrapped frames, so don't allow these frames |
|
2746 // to report child boxes. |
|
2747 return IsBoxFrame() ? GetFirstPrincipalChild() : nullptr; |
|
2748 } |
|
2749 nsIFrame* GetNextBox() const |
|
2750 { |
|
2751 return (mParent && mParent->IsBoxFrame()) ? mNextSibling : nullptr; |
|
2752 } |
|
2753 nsIFrame* GetParentBox() const |
|
2754 { |
|
2755 return (mParent && mParent->IsBoxFrame()) ? mParent : nullptr; |
|
2756 } |
|
2757 // Box methods. Note that these do NOT just get the CSS border, padding, |
|
2758 // etc. They also talk to nsITheme. |
|
2759 virtual nsresult GetBorderAndPadding(nsMargin& aBorderAndPadding); |
|
2760 virtual nsresult GetBorder(nsMargin& aBorder)=0; |
|
2761 virtual nsresult GetPadding(nsMargin& aBorderAndPadding)=0; |
|
2762 virtual nsresult GetMargin(nsMargin& aMargin)=0; |
|
2763 virtual void SetLayoutManager(nsBoxLayout* aLayout) { } |
|
2764 virtual nsBoxLayout* GetLayoutManager() { return nullptr; } |
|
2765 NS_HIDDEN_(nsresult) GetClientRect(nsRect& aContentRect); |
|
2766 |
|
2767 // For nsSprocketLayout |
|
2768 virtual Valignment GetVAlign() const = 0; |
|
2769 virtual Halignment GetHAlign() const = 0; |
|
2770 |
|
2771 bool IsHorizontal() const { return (mState & NS_STATE_IS_HORIZONTAL) != 0; } |
|
2772 bool IsNormalDirection() const { return (mState & NS_STATE_IS_DIRECTION_NORMAL) != 0; } |
|
2773 |
|
2774 NS_HIDDEN_(nsresult) Redraw(nsBoxLayoutState& aState); |
|
2775 virtual nsresult RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIFrame* aChild)=0; |
|
2776 // XXX take this out after we've branched |
|
2777 virtual bool GetMouseThrough() const { return false; } |
|
2778 |
|
2779 #ifdef DEBUG_LAYOUT |
|
2780 virtual nsresult SetDebug(nsBoxLayoutState& aState, bool aDebug)=0; |
|
2781 virtual nsresult GetDebug(bool& aDebug)=0; |
|
2782 |
|
2783 virtual nsresult DumpBox(FILE* out)=0; |
|
2784 #endif |
|
2785 |
|
2786 /** |
|
2787 * @return true if this text frame ends with a newline character. It |
|
2788 * should return false if this is not a text frame. |
|
2789 */ |
|
2790 virtual bool HasSignificantTerminalNewline() const; |
|
2791 |
|
2792 static bool AddCSSPrefSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth, bool& aHeightSet); |
|
2793 static bool AddCSSMinSize(nsBoxLayoutState& aState, nsIFrame* aBox, |
|
2794 nsSize& aSize, bool& aWidth, bool& aHeightSet); |
|
2795 static bool AddCSSMaxSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth, bool& aHeightSet); |
|
2796 static bool AddCSSFlex(nsBoxLayoutState& aState, nsIFrame* aBox, nscoord& aFlex); |
|
2797 |
|
2798 // END OF BOX LAYOUT METHODS |
|
2799 // The above methods have been migrated from nsIBox and are in the process of |
|
2800 // being refactored. DO NOT USE OUTSIDE OF XUL. |
|
2801 |
|
2802 struct CaretPosition { |
|
2803 CaretPosition(); |
|
2804 ~CaretPosition(); |
|
2805 |
|
2806 nsCOMPtr<nsIContent> mResultContent; |
|
2807 int32_t mContentOffset; |
|
2808 }; |
|
2809 |
|
2810 /** |
|
2811 * gets the first or last possible caret position within the frame |
|
2812 * |
|
2813 * @param [in] aStart |
|
2814 * true for getting the first possible caret position |
|
2815 * false for getting the last possible caret position |
|
2816 * @return The caret position in a CaretPosition. |
|
2817 * the returned value is a 'best effort' in case errors |
|
2818 * are encountered rummaging through the frame. |
|
2819 */ |
|
2820 CaretPosition GetExtremeCaretPosition(bool aStart); |
|
2821 |
|
2822 /** |
|
2823 * Get a line iterator for this frame, if supported. |
|
2824 * |
|
2825 * @return nullptr if no line iterator is supported. |
|
2826 * @note dispose the line iterator using nsILineIterator::DisposeLineIterator |
|
2827 */ |
|
2828 virtual nsILineIterator* GetLineIterator() = 0; |
|
2829 |
|
2830 /** |
|
2831 * If this frame is a next-in-flow, and its prev-in-flow has something on its |
|
2832 * overflow list, pull those frames into the child list of this one. |
|
2833 */ |
|
2834 virtual void PullOverflowsFromPrevInFlow() {} |
|
2835 |
|
2836 /** |
|
2837 * Clear the list of child PresShells generated during the last paint |
|
2838 * so that we can begin generating a new one. |
|
2839 */ |
|
2840 void ClearPresShellsFromLastPaint() { |
|
2841 PaintedPresShellList()->Clear(); |
|
2842 } |
|
2843 |
|
2844 /** |
|
2845 * Flag a child PresShell as painted so that it will get its paint count |
|
2846 * incremented during empty transactions. |
|
2847 */ |
|
2848 void AddPaintedPresShell(nsIPresShell* shell) { |
|
2849 nsWeakPtr weakShell = do_GetWeakReference(shell); |
|
2850 PaintedPresShellList()->AppendElement(weakShell); |
|
2851 } |
|
2852 |
|
2853 /** |
|
2854 * Increment the paint count of all child PresShells that were painted during |
|
2855 * the last repaint. |
|
2856 */ |
|
2857 void UpdatePaintCountForPaintedPresShells() { |
|
2858 nsTArray<nsWeakPtr> * list = PaintedPresShellList(); |
|
2859 for (int i = 0, l = list->Length(); i < l; i++) { |
|
2860 nsCOMPtr<nsIPresShell> shell = do_QueryReferent(list->ElementAt(i)); |
|
2861 |
|
2862 if (shell) { |
|
2863 shell->IncrementPaintCount(); |
|
2864 } |
|
2865 } |
|
2866 } |
|
2867 |
|
2868 /** |
|
2869 * Accessors for the absolute containing block. |
|
2870 */ |
|
2871 bool IsAbsoluteContainer() const { return !!(mState & NS_FRAME_HAS_ABSPOS_CHILDREN); } |
|
2872 bool HasAbsolutelyPositionedChildren() const; |
|
2873 nsAbsoluteContainingBlock* GetAbsoluteContainingBlock() const; |
|
2874 void MarkAsAbsoluteContainingBlock(); |
|
2875 void MarkAsNotAbsoluteContainingBlock(); |
|
2876 // Child frame types override this function to select their own child list name |
|
2877 virtual mozilla::layout::FrameChildListID GetAbsoluteListID() const { return kAbsoluteList; } |
|
2878 |
|
2879 // Checks if we (or any of our descendents) have NS_FRAME_PAINTED_THEBES set, and |
|
2880 // clears this bit if so. |
|
2881 bool CheckAndClearPaintedState(); |
|
2882 |
|
2883 // CSS visibility just doesn't cut it because it doesn't inherit through |
|
2884 // documents. Also if this frame is in a hidden card of a deck then it isn't |
|
2885 // visible either and that isn't expressed using CSS visibility. Also if it |
|
2886 // is in a hidden view (there are a few cases left and they are hopefully |
|
2887 // going away soon). |
|
2888 // If the VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY flag is passed then we |
|
2889 // ignore the chrome/content boundary, otherwise we stop looking when we |
|
2890 // reach it. |
|
2891 enum { |
|
2892 VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY = 0x01 |
|
2893 }; |
|
2894 bool IsVisibleConsideringAncestors(uint32_t aFlags = 0) const; |
|
2895 |
|
2896 struct FrameWithDistance |
|
2897 { |
|
2898 nsIFrame* mFrame; |
|
2899 nscoord mXDistance; |
|
2900 nscoord mYDistance; |
|
2901 }; |
|
2902 |
|
2903 /** |
|
2904 * Finds a frame that is closer to a specified point than a current |
|
2905 * distance. Distance is measured as for text selection -- a closer x |
|
2906 * distance beats a closer y distance. |
|
2907 * |
|
2908 * Normally, this function will only check the distance between this |
|
2909 * frame's rectangle and the specified point. SVGTextFrame overrides |
|
2910 * this so that it can manage all of its descendant frames and take |
|
2911 * into account any SVG text layout. |
|
2912 * |
|
2913 * If aPoint is closer to this frame's rectangle than aCurrentBestFrame |
|
2914 * indicates, then aCurrentBestFrame is updated with the distance between |
|
2915 * aPoint and this frame's rectangle, and with a pointer to this frame. |
|
2916 * If aPoint is not closer, then aCurrentBestFrame is left unchanged. |
|
2917 * |
|
2918 * @param aPoint The point to check for its distance to this frame. |
|
2919 * @param aCurrentBestFrame Pointer to a struct that will be updated with |
|
2920 * a pointer to this frame and its distance to aPoint, if this frame |
|
2921 * is indeed closer than the current distance in aCurrentBestFrame. |
|
2922 */ |
|
2923 virtual void FindCloserFrameForSelection(nsPoint aPoint, |
|
2924 FrameWithDistance* aCurrentBestFrame); |
|
2925 |
|
2926 /** |
|
2927 * Is this a flex item? (i.e. a non-abs-pos child of a flex container) |
|
2928 */ |
|
2929 inline bool IsFlexItem() const; |
|
2930 |
|
2931 inline bool IsBlockInside() const; |
|
2932 inline bool IsBlockOutside() const; |
|
2933 inline bool IsInlineOutside() const; |
|
2934 inline uint8_t GetDisplay() const; |
|
2935 inline bool IsFloating() const; |
|
2936 inline bool IsPositioned() const; |
|
2937 inline bool IsRelativelyPositioned() const; |
|
2938 inline bool IsAbsolutelyPositioned() const; |
|
2939 |
|
2940 /** |
|
2941 * Returns the vertical-align value to be used for layout, if it is one |
|
2942 * of the enumerated values. If this is an SVG text frame, it returns a value |
|
2943 * that corresponds to the value of dominant-baseline. If the |
|
2944 * vertical-align property has length or percentage value, this returns |
|
2945 * eInvalidVerticalAlign. |
|
2946 */ |
|
2947 uint8_t VerticalAlignEnum() const; |
|
2948 enum { eInvalidVerticalAlign = 0xFF }; |
|
2949 |
|
2950 bool IsSVGText() const { return mState & NS_FRAME_IS_SVG_TEXT; } |
|
2951 |
|
2952 void CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder, nsDisplayList* aList); |
|
2953 |
|
2954 /** |
|
2955 * Adds the NS_FRAME_IN_POPUP state bit to aFrame, and |
|
2956 * all descendant frames (including cross-doc ones). |
|
2957 */ |
|
2958 static void AddInPopupStateBitToDescendants(nsIFrame* aFrame); |
|
2959 /** |
|
2960 * Removes the NS_FRAME_IN_POPUP state bit from aFrame and |
|
2961 * all descendant frames (including cross-doc ones), unless |
|
2962 * the frame is a popup itself. |
|
2963 */ |
|
2964 static void RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame); |
|
2965 |
|
2966 /** |
|
2967 * Sorts the given nsFrameList, so that for every two adjacent frames in the |
|
2968 * list, the former is less than or equal to the latter, according to the |
|
2969 * templated IsLessThanOrEqual method. |
|
2970 * |
|
2971 * Note: this method uses a stable merge-sort algorithm. |
|
2972 */ |
|
2973 template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)> |
|
2974 static void SortFrameList(nsFrameList& aFrameList); |
|
2975 |
|
2976 /** |
|
2977 * Returns true if the given frame list is already sorted, according to the |
|
2978 * templated IsLessThanOrEqual function. |
|
2979 */ |
|
2980 template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)> |
|
2981 static bool IsFrameListSorted(nsFrameList& aFrameList); |
|
2982 |
|
2983 /** |
|
2984 * Return true if aFrame is in an {ib} split and is NOT one of the |
|
2985 * continuations of the first inline in it. |
|
2986 */ |
|
2987 bool FrameIsNonFirstInIBSplit() const { |
|
2988 return (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) && |
|
2989 FirstContinuation()->Properties().Get(nsIFrame::IBSplitPrevSibling()); |
|
2990 } |
|
2991 |
|
2992 /** |
|
2993 * Return true if aFrame is in an {ib} split and is NOT one of the |
|
2994 * continuations of the last inline in it. |
|
2995 */ |
|
2996 bool FrameIsNonLastInIBSplit() const { |
|
2997 return (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) && |
|
2998 FirstContinuation()->Properties().Get(nsIFrame::IBSplitSibling()); |
|
2999 } |
|
3000 |
|
3001 /** |
|
3002 * Return whether this is a frame whose width is used when computing |
|
3003 * the font size inflation of its descendants. |
|
3004 */ |
|
3005 bool IsContainerForFontSizeInflation() const { |
|
3006 return GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER; |
|
3007 } |
|
3008 |
|
3009 /** |
|
3010 * Returns the content node within the anonymous content that this frame |
|
3011 * generated and which corresponds to the specified pseudo-element type, |
|
3012 * or nullptr if there is no such anonymous content. |
|
3013 */ |
|
3014 virtual mozilla::dom::Element* GetPseudoElement(nsCSSPseudoElements::Type aType); |
|
3015 |
|
3016 protected: |
|
3017 // Members |
|
3018 nsRect mRect; |
|
3019 nsIContent* mContent; |
|
3020 nsStyleContext* mStyleContext; |
|
3021 nsIFrame* mParent; |
|
3022 private: |
|
3023 nsIFrame* mNextSibling; // doubly-linked list of frames |
|
3024 nsIFrame* mPrevSibling; // Do not touch outside SetNextSibling! |
|
3025 |
|
3026 void MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect); |
|
3027 |
|
3028 static void DestroyPaintedPresShellList(void* propertyValue) { |
|
3029 nsTArray<nsWeakPtr>* list = static_cast<nsTArray<nsWeakPtr>*>(propertyValue); |
|
3030 list->Clear(); |
|
3031 delete list; |
|
3032 } |
|
3033 |
|
3034 // Stores weak references to all the PresShells that were painted during |
|
3035 // the last paint event so that we can increment their paint count during |
|
3036 // empty transactions |
|
3037 NS_DECLARE_FRAME_PROPERTY(PaintedPresShellsProperty, DestroyPaintedPresShellList) |
|
3038 |
|
3039 nsTArray<nsWeakPtr>* PaintedPresShellList() { |
|
3040 nsTArray<nsWeakPtr>* list = static_cast<nsTArray<nsWeakPtr>*>( |
|
3041 Properties().Get(PaintedPresShellsProperty()) |
|
3042 ); |
|
3043 |
|
3044 if (!list) { |
|
3045 list = new nsTArray<nsWeakPtr>(); |
|
3046 Properties().Set(PaintedPresShellsProperty(), list); |
|
3047 } |
|
3048 |
|
3049 return list; |
|
3050 } |
|
3051 |
|
3052 protected: |
|
3053 nsFrameState mState; |
|
3054 |
|
3055 // When there is an overflow area only slightly larger than mRect, |
|
3056 // we store a set of four 1-byte deltas from the edges of mRect |
|
3057 // rather than allocating a whole separate rectangle property. |
|
3058 // Note that these are unsigned values, all measured "outwards" |
|
3059 // from the edges of mRect, so /mLeft/ and /mTop/ are reversed from |
|
3060 // our normal coordinate system. |
|
3061 // If mOverflow.mType == NS_FRAME_OVERFLOW_LARGE, then the |
|
3062 // delta values are not meaningful and the overflow area is stored |
|
3063 // as a separate rect property. |
|
3064 struct VisualDeltas { |
|
3065 uint8_t mLeft; |
|
3066 uint8_t mTop; |
|
3067 uint8_t mRight; |
|
3068 uint8_t mBottom; |
|
3069 bool operator==(const VisualDeltas& aOther) const |
|
3070 { |
|
3071 return mLeft == aOther.mLeft && mTop == aOther.mTop && |
|
3072 mRight == aOther.mRight && mBottom == aOther.mBottom; |
|
3073 } |
|
3074 bool operator!=(const VisualDeltas& aOther) const |
|
3075 { |
|
3076 return !(*this == aOther); |
|
3077 } |
|
3078 }; |
|
3079 union { |
|
3080 uint32_t mType; |
|
3081 VisualDeltas mVisualDeltas; |
|
3082 } mOverflow; |
|
3083 |
|
3084 // Helpers |
|
3085 /** |
|
3086 * Can we stop inside this frame when we're skipping non-rendered whitespace? |
|
3087 * @param aForward [in] Are we moving forward (or backward) in content order. |
|
3088 * @param aOffset [in/out] At what offset into the frame to start looking. |
|
3089 * on output - what offset was reached (whether or not we found a place to stop). |
|
3090 * @return STOP: An appropriate offset was found within this frame, |
|
3091 * and is given by aOffset. |
|
3092 * CONTINUE: Not found within this frame, need to try the next frame. |
|
3093 * see enum FrameSearchResult for more details. |
|
3094 */ |
|
3095 virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) = 0; |
|
3096 |
|
3097 /** |
|
3098 * Search the frame for the next character |
|
3099 * @param aForward [in] Are we moving forward (or backward) in content order. |
|
3100 * @param aOffset [in/out] At what offset into the frame to start looking. |
|
3101 * on output - what offset was reached (whether or not we found a place to stop). |
|
3102 * @param aRespectClusters [in] Whether to restrict result to valid cursor locations |
|
3103 * (between grapheme clusters) - default TRUE maintains "normal" behavior, |
|
3104 * FALSE is used for selection by "code unit" (instead of "character") |
|
3105 * @return STOP: An appropriate offset was found within this frame, |
|
3106 * and is given by aOffset. |
|
3107 * CONTINUE: Not found within this frame, need to try the next frame. |
|
3108 * see enum FrameSearchResult for more details. |
|
3109 */ |
|
3110 virtual FrameSearchResult PeekOffsetCharacter(bool aForward, int32_t* aOffset, |
|
3111 bool aRespectClusters = true) = 0; |
|
3112 |
|
3113 /** |
|
3114 * Search the frame for the next word boundary |
|
3115 * @param aForward [in] Are we moving forward (or backward) in content order. |
|
3116 * @param aWordSelectEatSpace [in] true: look for non-whitespace following |
|
3117 * whitespace (in the direction of movement). |
|
3118 * false: look for whitespace following non-whitespace (in the |
|
3119 * direction of movement). |
|
3120 * @param aIsKeyboardSelect [in] Was the action initiated by a keyboard operation? |
|
3121 * If true, punctuation immediately following a word is considered part |
|
3122 * of that word. Otherwise, a sequence of punctuation is always considered |
|
3123 * as a word on its own. |
|
3124 * @param aOffset [in/out] At what offset into the frame to start looking. |
|
3125 * on output - what offset was reached (whether or not we found a place to stop). |
|
3126 * @param aState [in/out] the state that is carried from frame to frame |
|
3127 * @return true: An appropriate offset was found within this frame, |
|
3128 * and is given by aOffset. |
|
3129 * false: Not found within this frame, need to try the next frame. |
|
3130 */ |
|
3131 struct PeekWordState { |
|
3132 // true when we're still at the start of the search, i.e., we can't return |
|
3133 // this point as a valid offset! |
|
3134 bool mAtStart; |
|
3135 // true when we've encountered at least one character of the pre-boundary type |
|
3136 // (whitespace if aWordSelectEatSpace is true, non-whitespace otherwise) |
|
3137 bool mSawBeforeType; |
|
3138 // true when the last character encountered was punctuation |
|
3139 bool mLastCharWasPunctuation; |
|
3140 // true when the last character encountered was whitespace |
|
3141 bool mLastCharWasWhitespace; |
|
3142 // true when we've seen non-punctuation since the last whitespace |
|
3143 bool mSeenNonPunctuationSinceWhitespace; |
|
3144 // text that's *before* the current frame when aForward is true, *after* |
|
3145 // the current frame when aForward is false. Only includes the text |
|
3146 // on the current line. |
|
3147 nsAutoString mContext; |
|
3148 |
|
3149 PeekWordState() : mAtStart(true), mSawBeforeType(false), |
|
3150 mLastCharWasPunctuation(false), mLastCharWasWhitespace(false), |
|
3151 mSeenNonPunctuationSinceWhitespace(false) {} |
|
3152 void SetSawBeforeType() { mSawBeforeType = true; } |
|
3153 void Update(bool aAfterPunctuation, bool aAfterWhitespace) { |
|
3154 mLastCharWasPunctuation = aAfterPunctuation; |
|
3155 mLastCharWasWhitespace = aAfterWhitespace; |
|
3156 if (aAfterWhitespace) { |
|
3157 mSeenNonPunctuationSinceWhitespace = false; |
|
3158 } else if (!aAfterPunctuation) { |
|
3159 mSeenNonPunctuationSinceWhitespace = true; |
|
3160 } |
|
3161 mAtStart = false; |
|
3162 } |
|
3163 }; |
|
3164 virtual FrameSearchResult PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect, |
|
3165 int32_t* aOffset, PeekWordState* aState) = 0; |
|
3166 |
|
3167 /** |
|
3168 * Search for the first paragraph boundary before or after the given position |
|
3169 * @param aPos See description in nsFrameSelection.h. The following fields are |
|
3170 * used by this method: |
|
3171 * Input: mDirection |
|
3172 * Output: mResultContent, mContentOffset |
|
3173 */ |
|
3174 nsresult PeekOffsetParagraph(nsPeekOffsetStruct *aPos); |
|
3175 |
|
3176 private: |
|
3177 nsOverflowAreas* GetOverflowAreasProperty(); |
|
3178 nsRect GetVisualOverflowFromDeltas() const { |
|
3179 NS_ABORT_IF_FALSE(mOverflow.mType != NS_FRAME_OVERFLOW_LARGE, |
|
3180 "should not be called when overflow is in a property"); |
|
3181 // Calculate the rect using deltas from the frame's border rect. |
|
3182 // Note that the mOverflow.mDeltas fields are unsigned, but we will often |
|
3183 // need to return negative values for the left and top, so take care |
|
3184 // to cast away the unsigned-ness. |
|
3185 return nsRect(-(int32_t)mOverflow.mVisualDeltas.mLeft, |
|
3186 -(int32_t)mOverflow.mVisualDeltas.mTop, |
|
3187 mRect.width + mOverflow.mVisualDeltas.mRight + |
|
3188 mOverflow.mVisualDeltas.mLeft, |
|
3189 mRect.height + mOverflow.mVisualDeltas.mBottom + |
|
3190 mOverflow.mVisualDeltas.mTop); |
|
3191 } |
|
3192 /** |
|
3193 * Returns true if any overflow changed. |
|
3194 */ |
|
3195 bool SetOverflowAreas(const nsOverflowAreas& aOverflowAreas); |
|
3196 nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther, const int32_t aAPD) const; |
|
3197 |
|
3198 // Helper-functions for SortFrameList(): |
|
3199 template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)> |
|
3200 static nsIFrame* SortedMerge(nsIFrame *aLeft, nsIFrame *aRight); |
|
3201 |
|
3202 template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)> |
|
3203 static nsIFrame* MergeSort(nsIFrame *aSource); |
|
3204 |
|
3205 bool HasOpacityInternal(float aThreshold) const; |
|
3206 |
|
3207 #ifdef DEBUG_FRAME_DUMP |
|
3208 public: |
|
3209 static void IndentBy(FILE* out, int32_t aIndent) { |
|
3210 while (--aIndent >= 0) fputs(" ", out); |
|
3211 } |
|
3212 void ListTag(FILE* out) const { |
|
3213 ListTag(out, this); |
|
3214 } |
|
3215 static void ListTag(FILE* out, const nsIFrame* aFrame) { |
|
3216 nsAutoCString t; |
|
3217 ListTag(t, aFrame); |
|
3218 fputs(t.get(), out); |
|
3219 } |
|
3220 void ListTag(nsACString& aTo) const; |
|
3221 static void ListTag(nsACString& aTo, const nsIFrame* aFrame); |
|
3222 void ListGeneric(nsACString& aTo, const char* aPrefix = "", uint32_t aFlags = 0) const; |
|
3223 enum { |
|
3224 TRAVERSE_SUBDOCUMENT_FRAMES = 0x01 |
|
3225 }; |
|
3226 virtual void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const; |
|
3227 /** |
|
3228 * lists the frames beginning from the root frame |
|
3229 * - calls root frame's List(...) |
|
3230 */ |
|
3231 static void RootFrameList(nsPresContext* aPresContext, |
|
3232 FILE* out = stderr, const char* aPrefix = ""); |
|
3233 virtual void DumpFrameTree(); |
|
3234 void DumpFrameTreeLimited(); |
|
3235 |
|
3236 virtual nsresult GetFrameName(nsAString& aResult) const = 0; |
|
3237 #endif |
|
3238 |
|
3239 #ifdef DEBUG |
|
3240 public: |
|
3241 virtual nsFrameState GetDebugStateBits() const = 0; |
|
3242 virtual nsresult DumpRegressionData(nsPresContext* aPresContext, |
|
3243 FILE* out, int32_t aIndent) = 0; |
|
3244 #endif |
|
3245 }; |
|
3246 |
|
3247 //---------------------------------------------------------------------- |
|
3248 |
|
3249 /** |
|
3250 * nsWeakFrame can be used to keep a reference to a nsIFrame in a safe way. |
|
3251 * Whenever an nsIFrame object is deleted, the nsWeakFrames pointing |
|
3252 * to it will be cleared. |
|
3253 * |
|
3254 * Create nsWeakFrame object when it is sure that nsIFrame object |
|
3255 * is alive and after some operations which may destroy the nsIFrame |
|
3256 * (for example any DOM modifications) use IsAlive() or GetFrame() methods to |
|
3257 * check whether it is safe to continue to use the nsIFrame object. |
|
3258 * |
|
3259 * @note The usage of this class should be kept to a minimum. |
|
3260 */ |
|
3261 |
|
3262 class nsWeakFrame { |
|
3263 public: |
|
3264 nsWeakFrame() : mPrev(nullptr), mFrame(nullptr) { } |
|
3265 |
|
3266 nsWeakFrame(const nsWeakFrame& aOther) : mPrev(nullptr), mFrame(nullptr) |
|
3267 { |
|
3268 Init(aOther.GetFrame()); |
|
3269 } |
|
3270 |
|
3271 nsWeakFrame(nsIFrame* aFrame) : mPrev(nullptr), mFrame(nullptr) |
|
3272 { |
|
3273 Init(aFrame); |
|
3274 } |
|
3275 |
|
3276 nsWeakFrame& operator=(nsWeakFrame& aOther) { |
|
3277 Init(aOther.GetFrame()); |
|
3278 return *this; |
|
3279 } |
|
3280 |
|
3281 nsWeakFrame& operator=(nsIFrame* aFrame) { |
|
3282 Init(aFrame); |
|
3283 return *this; |
|
3284 } |
|
3285 |
|
3286 nsIFrame* operator->() |
|
3287 { |
|
3288 return mFrame; |
|
3289 } |
|
3290 |
|
3291 operator nsIFrame*() |
|
3292 { |
|
3293 return mFrame; |
|
3294 } |
|
3295 |
|
3296 void Clear(nsIPresShell* aShell) { |
|
3297 if (aShell) { |
|
3298 aShell->RemoveWeakFrame(this); |
|
3299 } |
|
3300 mFrame = nullptr; |
|
3301 mPrev = nullptr; |
|
3302 } |
|
3303 |
|
3304 bool IsAlive() { return !!mFrame; } |
|
3305 |
|
3306 nsIFrame* GetFrame() const { return mFrame; } |
|
3307 |
|
3308 nsWeakFrame* GetPreviousWeakFrame() { return mPrev; } |
|
3309 |
|
3310 void SetPreviousWeakFrame(nsWeakFrame* aPrev) { mPrev = aPrev; } |
|
3311 |
|
3312 ~nsWeakFrame() |
|
3313 { |
|
3314 Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr); |
|
3315 } |
|
3316 private: |
|
3317 void Init(nsIFrame* aFrame); |
|
3318 |
|
3319 nsWeakFrame* mPrev; |
|
3320 nsIFrame* mFrame; |
|
3321 }; |
|
3322 |
|
3323 inline bool |
|
3324 nsFrameList::ContinueRemoveFrame(nsIFrame* aFrame) |
|
3325 { |
|
3326 MOZ_ASSERT(!aFrame->GetPrevSibling() || !aFrame->GetNextSibling(), |
|
3327 "Forgot to call StartRemoveFrame?"); |
|
3328 if (aFrame == mLastChild) { |
|
3329 MOZ_ASSERT(!aFrame->GetNextSibling(), "broken frame list"); |
|
3330 nsIFrame* prevSibling = aFrame->GetPrevSibling(); |
|
3331 if (!prevSibling) { |
|
3332 MOZ_ASSERT(aFrame == mFirstChild, "broken frame list"); |
|
3333 mFirstChild = mLastChild = nullptr; |
|
3334 return true; |
|
3335 } |
|
3336 MOZ_ASSERT(prevSibling->GetNextSibling() == aFrame, "Broken frame linkage"); |
|
3337 prevSibling->SetNextSibling(nullptr); |
|
3338 mLastChild = prevSibling; |
|
3339 return true; |
|
3340 } |
|
3341 if (aFrame == mFirstChild) { |
|
3342 MOZ_ASSERT(!aFrame->GetPrevSibling(), "broken frame list"); |
|
3343 mFirstChild = aFrame->GetNextSibling(); |
|
3344 aFrame->SetNextSibling(nullptr); |
|
3345 MOZ_ASSERT(mFirstChild, "broken frame list"); |
|
3346 return true; |
|
3347 } |
|
3348 return false; |
|
3349 } |
|
3350 |
|
3351 inline bool |
|
3352 nsFrameList::StartRemoveFrame(nsIFrame* aFrame) |
|
3353 { |
|
3354 if (aFrame->GetPrevSibling() && aFrame->GetNextSibling()) { |
|
3355 UnhookFrameFromSiblings(aFrame); |
|
3356 return true; |
|
3357 } |
|
3358 return ContinueRemoveFrame(aFrame); |
|
3359 } |
|
3360 |
|
3361 inline void |
|
3362 nsFrameList::Enumerator::Next() |
|
3363 { |
|
3364 NS_ASSERTION(!AtEnd(), "Should have checked AtEnd()!"); |
|
3365 mFrame = mFrame->GetNextSibling(); |
|
3366 } |
|
3367 |
|
3368 inline |
|
3369 nsFrameList::FrameLinkEnumerator:: |
|
3370 FrameLinkEnumerator(const nsFrameList& aList, nsIFrame* aPrevFrame) |
|
3371 : Enumerator(aList) |
|
3372 { |
|
3373 mPrev = aPrevFrame; |
|
3374 mFrame = aPrevFrame ? aPrevFrame->GetNextSibling() : aList.FirstChild(); |
|
3375 } |
|
3376 |
|
3377 inline void |
|
3378 nsFrameList::FrameLinkEnumerator::Next() |
|
3379 { |
|
3380 mPrev = mFrame; |
|
3381 Enumerator::Next(); |
|
3382 } |
|
3383 |
|
3384 // Helper-functions for nsIFrame::SortFrameList() |
|
3385 // --------------------------------------------------- |
|
3386 |
|
3387 template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)> |
|
3388 /* static */ nsIFrame* |
|
3389 nsIFrame::SortedMerge(nsIFrame *aLeft, nsIFrame *aRight) |
|
3390 { |
|
3391 NS_PRECONDITION(aLeft && aRight, "SortedMerge must have non-empty lists"); |
|
3392 |
|
3393 nsIFrame *result; |
|
3394 // Unroll first iteration to avoid null-check 'result' inside the loop. |
|
3395 if (IsLessThanOrEqual(aLeft, aRight)) { |
|
3396 result = aLeft; |
|
3397 aLeft = aLeft->GetNextSibling(); |
|
3398 if (!aLeft) { |
|
3399 result->SetNextSibling(aRight); |
|
3400 return result; |
|
3401 } |
|
3402 } |
|
3403 else { |
|
3404 result = aRight; |
|
3405 aRight = aRight->GetNextSibling(); |
|
3406 if (!aRight) { |
|
3407 result->SetNextSibling(aLeft); |
|
3408 return result; |
|
3409 } |
|
3410 } |
|
3411 |
|
3412 nsIFrame *last = result; |
|
3413 for (;;) { |
|
3414 if (IsLessThanOrEqual(aLeft, aRight)) { |
|
3415 last->SetNextSibling(aLeft); |
|
3416 last = aLeft; |
|
3417 aLeft = aLeft->GetNextSibling(); |
|
3418 if (!aLeft) { |
|
3419 last->SetNextSibling(aRight); |
|
3420 return result; |
|
3421 } |
|
3422 } |
|
3423 else { |
|
3424 last->SetNextSibling(aRight); |
|
3425 last = aRight; |
|
3426 aRight = aRight->GetNextSibling(); |
|
3427 if (!aRight) { |
|
3428 last->SetNextSibling(aLeft); |
|
3429 return result; |
|
3430 } |
|
3431 } |
|
3432 } |
|
3433 } |
|
3434 |
|
3435 template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)> |
|
3436 /* static */ nsIFrame* |
|
3437 nsIFrame::MergeSort(nsIFrame *aSource) |
|
3438 { |
|
3439 NS_PRECONDITION(aSource, "MergeSort null arg"); |
|
3440 |
|
3441 nsIFrame *sorted[32] = { nullptr }; |
|
3442 nsIFrame **fill = &sorted[0]; |
|
3443 nsIFrame **left; |
|
3444 nsIFrame *rest = aSource; |
|
3445 |
|
3446 do { |
|
3447 nsIFrame *current = rest; |
|
3448 rest = rest->GetNextSibling(); |
|
3449 current->SetNextSibling(nullptr); |
|
3450 |
|
3451 // Merge it with sorted[0] if present; then merge the result with sorted[1] etc. |
|
3452 // sorted[0] is a list of length 1 (or nullptr). |
|
3453 // sorted[1] is a list of length 2 (or nullptr). |
|
3454 // sorted[2] is a list of length 4 (or nullptr). etc. |
|
3455 for (left = &sorted[0]; left != fill && *left; ++left) { |
|
3456 current = SortedMerge<IsLessThanOrEqual>(*left, current); |
|
3457 *left = nullptr; |
|
3458 } |
|
3459 |
|
3460 // Fill the empty slot that we couldn't merge with the last result. |
|
3461 *left = current; |
|
3462 |
|
3463 if (left == fill) |
|
3464 ++fill; |
|
3465 } while (rest); |
|
3466 |
|
3467 // Collect and merge the results. |
|
3468 nsIFrame *result = nullptr; |
|
3469 for (left = &sorted[0]; left != fill; ++left) { |
|
3470 if (*left) { |
|
3471 result = result ? SortedMerge<IsLessThanOrEqual>(*left, result) : *left; |
|
3472 } |
|
3473 } |
|
3474 return result; |
|
3475 } |
|
3476 |
|
3477 template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)> |
|
3478 /* static */ void |
|
3479 nsIFrame::SortFrameList(nsFrameList& aFrameList) |
|
3480 { |
|
3481 nsIFrame* head = MergeSort<IsLessThanOrEqual>(aFrameList.FirstChild()); |
|
3482 aFrameList = nsFrameList(head, nsLayoutUtils::GetLastSibling(head)); |
|
3483 MOZ_ASSERT(IsFrameListSorted<IsLessThanOrEqual>(aFrameList), |
|
3484 "After we sort a frame list, it should be in sorted order..."); |
|
3485 } |
|
3486 |
|
3487 template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)> |
|
3488 /* static */ bool |
|
3489 nsIFrame::IsFrameListSorted(nsFrameList& aFrameList) |
|
3490 { |
|
3491 if (aFrameList.IsEmpty()) { |
|
3492 // empty lists are trivially sorted. |
|
3493 return true; |
|
3494 } |
|
3495 |
|
3496 // We'll walk through the list with two iterators, one trailing behind the |
|
3497 // other. The list is sorted IFF trailingIter <= iter, across the whole list. |
|
3498 nsFrameList::Enumerator trailingIter(aFrameList); |
|
3499 nsFrameList::Enumerator iter(aFrameList); |
|
3500 iter.Next(); // Skip |iter| past first frame. (List is nonempty, so we can.) |
|
3501 |
|
3502 // Now, advance the iterators in parallel, comparing each adjacent pair. |
|
3503 while (!iter.AtEnd()) { |
|
3504 MOZ_ASSERT(!trailingIter.AtEnd(), "trailing iter shouldn't finish first"); |
|
3505 if (!IsLessThanOrEqual(trailingIter.get(), iter.get())) { |
|
3506 return false; |
|
3507 } |
|
3508 trailingIter.Next(); |
|
3509 iter.Next(); |
|
3510 } |
|
3511 |
|
3512 // We made it to the end without returning early, so the list is sorted. |
|
3513 return true; |
|
3514 } |
|
3515 |
|
3516 #endif /* nsIFrame_h___ */ |