Wed, 31 Dec 2014 06:09:35 +0100
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___ */ |