layout/generic/nsIFrame.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial