layout/generic/WritingModes.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifndef WritingModes_h_
michael@0 7 #define WritingModes_h_
michael@0 8
michael@0 9 #include "nsRect.h"
michael@0 10 #include "nsStyleStruct.h"
michael@0 11
michael@0 12 // If WRITING_MODE_VERTICAL_ENABLED is defined, we will attempt to support
michael@0 13 // the vertical writing-mode values; if it is not defined, then
michael@0 14 // WritingMode.IsVertical() will be hard-coded to return false, allowing
michael@0 15 // many conditional branches to be optimized away while we're in the process
michael@0 16 // of transitioning layout to use writing-mode and logical directions, but
michael@0 17 // not yet ready to ship vertical support.
michael@0 18
michael@0 19 /* #define WRITING_MODE_VERTICAL_ENABLED 1 */
michael@0 20
michael@0 21 // It is the caller's responsibility to operate on logical-coordinate objects
michael@0 22 // with matched writing modes. Failure to do so will be a runtime bug; the
michael@0 23 // compiler can't catch it, but in debug mode, we'll throw an assertion.
michael@0 24 // NOTE that in non-debug builds, a writing mode mismatch error will NOT be
michael@0 25 // detected, yet the results will be nonsense (and may lead to further layout
michael@0 26 // failures). Therefore, it is important to test (and fuzz-test) writing-mode
michael@0 27 // support using debug builds.
michael@0 28
michael@0 29 // Methods in logical-coordinate classes that take another logical-coordinate
michael@0 30 // object as a parameter should call CHECK_WRITING_MODE on it to verify that
michael@0 31 // the writing modes match.
michael@0 32 // (In some cases, there are internal (private) methods that don't do this;
michael@0 33 // such methods should only be used by other methods that have already checked
michael@0 34 // the writing modes.)
michael@0 35
michael@0 36 #define CHECK_WRITING_MODE(param) \
michael@0 37 NS_ASSERTION(param == mWritingMode, "writing-mode mismatch")
michael@0 38
michael@0 39 /**
michael@0 40 * mozilla::WritingMode is an immutable class representing a
michael@0 41 * writing mode.
michael@0 42 *
michael@0 43 * It efficiently stores the writing mode and can rapidly compute
michael@0 44 * interesting things about it for use in layout.
michael@0 45 *
michael@0 46 * Writing modes are computed from the CSS 'direction',
michael@0 47 * 'writing-mode', and 'text-orientation' properties.
michael@0 48 * See CSS3 Writing Modes for more information
michael@0 49 * http://www.w3.org/TR/css3-writing-modes/
michael@0 50 */
michael@0 51
michael@0 52 namespace mozilla {
michael@0 53
michael@0 54 class WritingMode {
michael@0 55 public:
michael@0 56 /**
michael@0 57 * Absolute inline flow direction
michael@0 58 */
michael@0 59 enum InlineDir {
michael@0 60 eInlineLTR = 0x00, // text flows horizontally left to right
michael@0 61 eInlineRTL = 0x02, // text flows horizontally right to left
michael@0 62 eInlineTTB = 0x01, // text flows vertically top to bottom
michael@0 63 eInlineBTT = 0x03, // text flows vertically bottom to top
michael@0 64 };
michael@0 65
michael@0 66 /**
michael@0 67 * Absolute block flow direction
michael@0 68 */
michael@0 69 enum BlockDir {
michael@0 70 eBlockTB = 0x00, // horizontal lines stack top to bottom
michael@0 71 eBlockRL = 0x01, // vertical lines stack right to left
michael@0 72 eBlockLR = 0x05, // vertical lines stack left to right
michael@0 73 };
michael@0 74
michael@0 75 /**
michael@0 76 * Line-relative (bidi-relative) inline flow direction
michael@0 77 */
michael@0 78 enum BidiDir {
michael@0 79 eBidiLTR = 0x00, // inline flow matches bidi LTR text
michael@0 80 eBidiRTL = 0x10, // inline flow matches bidi RTL text
michael@0 81 };
michael@0 82
michael@0 83 /**
michael@0 84 * Unknown writing mode (should never actually be stored or used anywhere).
michael@0 85 */
michael@0 86 enum {
michael@0 87 eUnknownWritingMode = 0xff
michael@0 88 };
michael@0 89
michael@0 90 /**
michael@0 91 * Return the absolute inline flow direction as an InlineDir
michael@0 92 */
michael@0 93 InlineDir GetInlineDir() const { return InlineDir(mWritingMode & eInlineMask); }
michael@0 94
michael@0 95 /**
michael@0 96 * Return the absolute block flow direction as a BlockDir
michael@0 97 */
michael@0 98 BlockDir GetBlockDir() const { return BlockDir(mWritingMode & eBlockMask); }
michael@0 99
michael@0 100 /**
michael@0 101 * Return the line-relative inline flow direction as a BidiDir
michael@0 102 */
michael@0 103 BidiDir GetBidiDir() const { return BidiDir(mWritingMode & eBidiMask); }
michael@0 104
michael@0 105 /**
michael@0 106 * Return true if LTR. (Convenience method)
michael@0 107 */
michael@0 108 bool IsBidiLTR() const { return eBidiLTR == (mWritingMode & eBidiMask); }
michael@0 109
michael@0 110 /**
michael@0 111 * True if vertical-mode block direction is LR (convenience method).
michael@0 112 */
michael@0 113 bool IsVerticalLR() const { return eBlockLR == (mWritingMode & eBlockMask); }
michael@0 114
michael@0 115 /**
michael@0 116 * True if vertical writing mode, i.e. when
michael@0 117 * writing-mode: vertical-lr | vertical-rl.
michael@0 118 */
michael@0 119 #ifdef WRITING_MODE_VERTICAL_ENABLED
michael@0 120 bool IsVertical() const { return !!(mWritingMode & eOrientationMask); }
michael@0 121 #else
michael@0 122 bool IsVertical() const { return false; }
michael@0 123 #endif
michael@0 124
michael@0 125 /**
michael@0 126 * True if line-over/line-under are inverted from block-start/block-end.
michael@0 127 * This is true when
michael@0 128 * - writing-mode is vertical-rl && text-orientation is sideways-left
michael@0 129 * - writing-mode is vertical-lr && text-orientation is not sideways-left
michael@0 130 */
michael@0 131 #ifdef WRITING_MODE_VERTICAL_ENABLED
michael@0 132 bool IsLineInverted() const { return !!(mWritingMode & eLineOrientMask); }
michael@0 133 #else
michael@0 134 bool IsLineInverted() const { return false; }
michael@0 135 #endif
michael@0 136
michael@0 137 /**
michael@0 138 * Block-axis flow-relative to line-relative factor.
michael@0 139 * May be used as a multiplication factor for block-axis coordinates
michael@0 140 * to convert between flow- and line-relative coordinate systems (e.g.
michael@0 141 * positioning an over- or under-line decoration).
michael@0 142 */
michael@0 143 int FlowRelativeToLineRelativeFactor() const
michael@0 144 {
michael@0 145 return IsLineInverted() ? -1 : 1;
michael@0 146 }
michael@0 147
michael@0 148 /**
michael@0 149 * Default constructor gives us a horizontal, LTR writing mode.
michael@0 150 * XXX We will probably eliminate this and require explicit initialization
michael@0 151 * in all cases once transition is complete.
michael@0 152 */
michael@0 153 WritingMode()
michael@0 154 : mWritingMode(0)
michael@0 155 { }
michael@0 156
michael@0 157 /**
michael@0 158 * Construct writing mode based on a style context
michael@0 159 */
michael@0 160 WritingMode(const nsStyleVisibility* aStyleVisibility)
michael@0 161 {
michael@0 162 NS_ASSERTION(aStyleVisibility, "we need an nsStyleVisibility here");
michael@0 163
michael@0 164 #ifdef WRITING_MODE_VERTICAL_ENABLED
michael@0 165 switch (aStyleVisibility->mWritingMode) {
michael@0 166 case NS_STYLE_WRITING_MODE_HORIZONTAL_TB:
michael@0 167 mWritingMode = 0;
michael@0 168 break;
michael@0 169
michael@0 170 case NS_STYLE_WRITING_MODE_VERTICAL_LR:
michael@0 171 mWritingMode = eBlockFlowMask |
michael@0 172 eLineOrientMask | //XXX needs update when text-orientation added
michael@0 173 eOrientationMask;
michael@0 174 break;
michael@0 175
michael@0 176 case NS_STYLE_WRITING_MODE_VERTICAL_RL:
michael@0 177 mWritingMode = eOrientationMask;
michael@0 178 break;
michael@0 179
michael@0 180 default:
michael@0 181 NS_NOTREACHED("unknown writing mode!");
michael@0 182 mWritingMode = 0;
michael@0 183 break;
michael@0 184 }
michael@0 185 #else
michael@0 186 mWritingMode = 0;
michael@0 187 #endif
michael@0 188
michael@0 189 if (NS_STYLE_DIRECTION_RTL == aStyleVisibility->mDirection) {
michael@0 190 mWritingMode |= eInlineFlowMask | //XXX needs update when text-orientation added
michael@0 191 eBidiMask;
michael@0 192 }
michael@0 193 }
michael@0 194
michael@0 195 // For unicode-bidi: plaintext, reset the direction of the writing mode from
michael@0 196 // the bidi paragraph level of the content
michael@0 197
michael@0 198 //XXX change uint8_t to UBiDiLevel after bug 924851
michael@0 199 void SetDirectionFromBidiLevel(uint8_t level)
michael@0 200 {
michael@0 201 if (level & 1) {
michael@0 202 // odd level, set RTL
michael@0 203 mWritingMode |= eBidiMask;
michael@0 204 } else {
michael@0 205 // even level, set LTR
michael@0 206 mWritingMode &= ~eBidiMask;
michael@0 207 }
michael@0 208 }
michael@0 209
michael@0 210 /**
michael@0 211 * Compare two WritingModes for equality.
michael@0 212 */
michael@0 213 bool operator==(const WritingMode& aOther) const
michael@0 214 {
michael@0 215 return mWritingMode == aOther.mWritingMode;
michael@0 216 }
michael@0 217
michael@0 218 private:
michael@0 219 friend class LogicalPoint;
michael@0 220 friend class LogicalSize;
michael@0 221 friend class LogicalMargin;
michael@0 222 friend class LogicalRect;
michael@0 223
michael@0 224 /**
michael@0 225 * Return a WritingMode representing an unknown value.
michael@0 226 */
michael@0 227 static inline WritingMode Unknown()
michael@0 228 {
michael@0 229 return WritingMode(eUnknownWritingMode);
michael@0 230 }
michael@0 231
michael@0 232 /**
michael@0 233 * Constructing a WritingMode with an arbitrary value is a private operation
michael@0 234 * currently only used by the Unknown() static method.
michael@0 235 */
michael@0 236 WritingMode(uint8_t aValue)
michael@0 237 : mWritingMode(aValue)
michael@0 238 { }
michael@0 239
michael@0 240 uint8_t mWritingMode;
michael@0 241
michael@0 242 enum Masks {
michael@0 243 // Masks for our bits; true chosen as opposite of commonest case
michael@0 244 eOrientationMask = 0x01, // true means vertical text
michael@0 245 eInlineFlowMask = 0x02, // true means absolute RTL/BTT (against physical coords)
michael@0 246 eBlockFlowMask = 0x04, // true means vertical-LR (or horizontal-BT if added)
michael@0 247 eLineOrientMask = 0x08, // true means over != block-start
michael@0 248 eBidiMask = 0x10, // true means line-relative RTL (bidi RTL)
michael@0 249 // Note: We have one excess bit of info; WritingMode can pack into 4 bits.
michael@0 250 // But since we have space, we're caching interesting things for fast access.
michael@0 251
michael@0 252 // Masks for output enums
michael@0 253 eInlineMask = 0x03,
michael@0 254 eBlockMask = 0x05
michael@0 255 };
michael@0 256 };
michael@0 257
michael@0 258
michael@0 259 /**
michael@0 260 * Logical-coordinate classes:
michael@0 261 *
michael@0 262 * There are three sets of coordinate space:
michael@0 263 * - physical (top, left, bottom, right)
michael@0 264 * relative to graphics coord system
michael@0 265 * - flow-relative (block-start, inline-start, block-end, inline-end)
michael@0 266 * relative to block/inline flow directions
michael@0 267 * - line-relative (line-over, line-left, line-under, line-right)
michael@0 268 * relative to glyph orientation / inline bidi directions
michael@0 269 * See CSS3 Writing Modes for more information
michael@0 270 * http://www.w3.org/TR/css3-writing-modes/#abstract-box
michael@0 271 *
michael@0 272 * For shorthand, B represents the block-axis
michael@0 273 * I represents the inline-axis
michael@0 274 *
michael@0 275 * The flow-relative geometric classes store coords in flow-relative space.
michael@0 276 * They use a private ns{Point,Size,Rect,Margin} member to store the actual
michael@0 277 * coordinate values, but reinterpret them as logical instead of physical.
michael@0 278 * This allows us to easily perform calculations in logical space (provided
michael@0 279 * writing modes of the operands match), by simply mapping to nsPoint (etc)
michael@0 280 * methods.
michael@0 281 *
michael@0 282 * Physical-coordinate accessors/setters are responsible to translate these
michael@0 283 * internal logical values as necessary.
michael@0 284 *
michael@0 285 * In DEBUG builds, the logical types store their WritingMode and check
michael@0 286 * that the same WritingMode is passed whenever callers ask them to do a
michael@0 287 * writing-mode-dependent operation. Non-DEBUG builds do NOT check this,
michael@0 288 * to avoid the overhead of storing WritingMode fields.
michael@0 289 *
michael@0 290 * Open question: do we need a different set optimized for line-relative
michael@0 291 * math, for use in nsLineLayout and the like? Or is multiplying values
michael@0 292 * by FlowRelativeToLineRelativeFactor() enough?
michael@0 293 */
michael@0 294
michael@0 295 /**
michael@0 296 * Flow-relative point
michael@0 297 */
michael@0 298 class LogicalPoint {
michael@0 299 public:
michael@0 300 LogicalPoint(WritingMode aWritingMode)
michael@0 301 :
michael@0 302 #ifdef DEBUG
michael@0 303 mWritingMode(aWritingMode),
michael@0 304 #endif
michael@0 305 mPoint(0, 0)
michael@0 306 { }
michael@0 307
michael@0 308 // Construct from a writing mode and individual coordinates (which MUST be
michael@0 309 // values in that writing mode, NOT physical coordinates!)
michael@0 310 LogicalPoint(WritingMode aWritingMode, nscoord aI, nscoord aB)
michael@0 311 :
michael@0 312 #ifdef DEBUG
michael@0 313 mWritingMode(aWritingMode),
michael@0 314 #endif
michael@0 315 mPoint(aI, aB)
michael@0 316 { }
michael@0 317
michael@0 318 // Construct from a writing mode and a physical point, within a given
michael@0 319 // containing rectangle's width (defining the conversion between LTR
michael@0 320 // and RTL coordinates).
michael@0 321 LogicalPoint(WritingMode aWritingMode,
michael@0 322 const nsPoint& aPoint,
michael@0 323 nscoord aContainerWidth)
michael@0 324 #ifdef DEBUG
michael@0 325 : mWritingMode(aWritingMode)
michael@0 326 #endif
michael@0 327 {
michael@0 328 if (aWritingMode.IsVertical()) {
michael@0 329 I() = aPoint.y;
michael@0 330 B() = aWritingMode.IsVerticalLR() ? aPoint.x : aContainerWidth - aPoint.x;
michael@0 331 } else {
michael@0 332 I() = aWritingMode.IsBidiLTR() ? aPoint.x : aContainerWidth - aPoint.x;
michael@0 333 B() = aPoint.y;
michael@0 334 }
michael@0 335 }
michael@0 336
michael@0 337 /**
michael@0 338 * Read-only (const) access to the coordinates, in both logical
michael@0 339 * and physical terms.
michael@0 340 */
michael@0 341 nscoord I(WritingMode aWritingMode) const // inline-axis
michael@0 342 {
michael@0 343 CHECK_WRITING_MODE(aWritingMode);
michael@0 344 return mPoint.x;
michael@0 345 }
michael@0 346 nscoord B(WritingMode aWritingMode) const // block-axis
michael@0 347 {
michael@0 348 CHECK_WRITING_MODE(aWritingMode);
michael@0 349 return mPoint.y;
michael@0 350 }
michael@0 351
michael@0 352 nscoord X(WritingMode aWritingMode, nscoord aContainerWidth) const
michael@0 353 {
michael@0 354 CHECK_WRITING_MODE(aWritingMode);
michael@0 355 if (aWritingMode.IsVertical()) {
michael@0 356 return aWritingMode.IsVerticalLR() ? B() : aContainerWidth - B();
michael@0 357 } else {
michael@0 358 return aWritingMode.IsBidiLTR() ? I() : aContainerWidth - I();
michael@0 359 }
michael@0 360 }
michael@0 361 nscoord Y(WritingMode aWritingMode) const
michael@0 362 {
michael@0 363 CHECK_WRITING_MODE(aWritingMode);
michael@0 364 return aWritingMode.IsVertical() ? I() : B();
michael@0 365 }
michael@0 366
michael@0 367 /**
michael@0 368 * These non-const accessors return a reference (lvalue) that can be
michael@0 369 * assigned to by callers.
michael@0 370 */
michael@0 371 nscoord& I(WritingMode aWritingMode) // inline-axis
michael@0 372 {
michael@0 373 CHECK_WRITING_MODE(aWritingMode);
michael@0 374 return mPoint.x;
michael@0 375 }
michael@0 376 nscoord& B(WritingMode aWritingMode) // block-axis
michael@0 377 {
michael@0 378 CHECK_WRITING_MODE(aWritingMode);
michael@0 379 return mPoint.y;
michael@0 380 }
michael@0 381
michael@0 382 /**
michael@0 383 * Setters for the physical coordinates.
michael@0 384 */
michael@0 385 void SetX(WritingMode aWritingMode, nscoord aX, nscoord aContainerWidth)
michael@0 386 {
michael@0 387 CHECK_WRITING_MODE(aWritingMode);
michael@0 388 if (aWritingMode.IsVertical()) {
michael@0 389 B() = aWritingMode.IsVerticalLR() ? aX : aContainerWidth - aX;
michael@0 390 } else {
michael@0 391 I() = aWritingMode.IsBidiLTR() ? aX : aContainerWidth - aX;
michael@0 392 }
michael@0 393 }
michael@0 394 void SetY(WritingMode aWritingMode, nscoord aY)
michael@0 395 {
michael@0 396 CHECK_WRITING_MODE(aWritingMode);
michael@0 397 if (aWritingMode.IsVertical()) {
michael@0 398 B() = aY;
michael@0 399 } else {
michael@0 400 I() = aY;
michael@0 401 }
michael@0 402 }
michael@0 403
michael@0 404 /**
michael@0 405 * Return a physical point corresponding to our logical coordinates,
michael@0 406 * converted according to our writing mode.
michael@0 407 */
michael@0 408 nsPoint GetPhysicalPoint(WritingMode aWritingMode,
michael@0 409 nscoord aContainerWidth) const
michael@0 410 {
michael@0 411 CHECK_WRITING_MODE(aWritingMode);
michael@0 412 if (aWritingMode.IsVertical()) {
michael@0 413 return nsPoint(aWritingMode.IsVerticalLR() ? B() : aContainerWidth - B(),
michael@0 414 I());
michael@0 415 } else {
michael@0 416 return nsPoint(aWritingMode.IsBidiLTR() ? I() : aContainerWidth - I(),
michael@0 417 B());
michael@0 418 }
michael@0 419 }
michael@0 420
michael@0 421 /**
michael@0 422 * Return the equivalent point in a different writing mode.
michael@0 423 */
michael@0 424 LogicalPoint ConvertTo(WritingMode aToMode, WritingMode aFromMode,
michael@0 425 nscoord aContainerWidth) const
michael@0 426 {
michael@0 427 CHECK_WRITING_MODE(aFromMode);
michael@0 428 return aToMode == aFromMode ?
michael@0 429 *this : LogicalPoint(aToMode,
michael@0 430 GetPhysicalPoint(aFromMode, aContainerWidth),
michael@0 431 aContainerWidth);
michael@0 432 }
michael@0 433
michael@0 434 LogicalPoint operator+(const LogicalPoint& aOther) const
michael@0 435 {
michael@0 436 CHECK_WRITING_MODE(aOther.GetWritingMode());
michael@0 437 // In non-debug builds, LogicalPoint does not store the WritingMode,
michael@0 438 // so the first parameter here (which will always be eUnknownWritingMode)
michael@0 439 // is ignored.
michael@0 440 return LogicalPoint(GetWritingMode(),
michael@0 441 mPoint.x + aOther.mPoint.x,
michael@0 442 mPoint.y + aOther.mPoint.y);
michael@0 443 }
michael@0 444
michael@0 445 private:
michael@0 446 friend class LogicalRect;
michael@0 447
michael@0 448 /**
michael@0 449 * NOTE that in non-DEBUG builds, GetWritingMode() always returns
michael@0 450 * eUnknownWritingMode, as the current mode is not stored in the logical-
michael@0 451 * geometry classes. Therefore, this method is private; it is used ONLY
michael@0 452 * by the DEBUG-mode checking macros in this class and its friends;
michael@0 453 * other code is not allowed to ask a logical point for its writing mode,
michael@0 454 * as this info will simply not be available in non-DEBUG builds.
michael@0 455 *
michael@0 456 * Also, in non-DEBUG builds, CHECK_WRITING_MODE does nothing, and the
michael@0 457 * WritingMode parameter to logical methods will generally be optimized
michael@0 458 * away altogether.
michael@0 459 */
michael@0 460 #ifdef DEBUG
michael@0 461 WritingMode GetWritingMode() const { return mWritingMode; }
michael@0 462 #else
michael@0 463 WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
michael@0 464 #endif
michael@0 465
michael@0 466 // We don't allow construction of a LogicalPoint with no writing mode.
michael@0 467 LogicalPoint() MOZ_DELETE;
michael@0 468
michael@0 469 // Accessors that don't take or check a WritingMode value.
michael@0 470 // These are for internal use only; they are called by methods that have
michael@0 471 // themselves already checked the WritingMode passed by the caller.
michael@0 472 nscoord I() const // inline-axis
michael@0 473 {
michael@0 474 return mPoint.x;
michael@0 475 }
michael@0 476 nscoord B() const // block-axis
michael@0 477 {
michael@0 478 return mPoint.y;
michael@0 479 }
michael@0 480
michael@0 481 nscoord& I() // inline-axis
michael@0 482 {
michael@0 483 return mPoint.x;
michael@0 484 }
michael@0 485 nscoord& B() // block-axis
michael@0 486 {
michael@0 487 return mPoint.y;
michael@0 488 }
michael@0 489
michael@0 490 WritingMode mWritingMode;
michael@0 491
michael@0 492 // We use an nsPoint to hold the coordinates, but reinterpret its .x and .y
michael@0 493 // fields as the inline and block directions. Hence, this is not exposed
michael@0 494 // directly, but only through accessors that will map them according to the
michael@0 495 // writing mode.
michael@0 496 nsPoint mPoint;
michael@0 497 };
michael@0 498
michael@0 499 /**
michael@0 500 * Flow-relative size
michael@0 501 */
michael@0 502 class LogicalSize {
michael@0 503 public:
michael@0 504 LogicalSize(WritingMode aWritingMode)
michael@0 505 :
michael@0 506 #ifdef DEBUG
michael@0 507 mWritingMode(aWritingMode),
michael@0 508 #endif
michael@0 509 mSize(0, 0)
michael@0 510 { }
michael@0 511
michael@0 512 LogicalSize(WritingMode aWritingMode, nscoord aISize, nscoord aBSize)
michael@0 513 :
michael@0 514 #ifdef DEBUG
michael@0 515 mWritingMode(aWritingMode),
michael@0 516 #endif
michael@0 517 mSize(aISize, aBSize)
michael@0 518 { }
michael@0 519
michael@0 520 LogicalSize(WritingMode aWritingMode, const nsSize& aPhysicalSize)
michael@0 521 #ifdef DEBUG
michael@0 522 : mWritingMode(aWritingMode)
michael@0 523 #endif
michael@0 524 {
michael@0 525 if (aWritingMode.IsVertical()) {
michael@0 526 ISize() = aPhysicalSize.height;
michael@0 527 BSize() = aPhysicalSize.width;
michael@0 528 } else {
michael@0 529 ISize() = aPhysicalSize.width;
michael@0 530 BSize() = aPhysicalSize.height;
michael@0 531 }
michael@0 532 }
michael@0 533
michael@0 534 /**
michael@0 535 * Dimensions in logical and physical terms
michael@0 536 */
michael@0 537 nscoord ISize(WritingMode aWritingMode) const // inline-size
michael@0 538 {
michael@0 539 CHECK_WRITING_MODE(aWritingMode);
michael@0 540 return mSize.width;
michael@0 541 }
michael@0 542 nscoord BSize(WritingMode aWritingMode) const // block-size
michael@0 543 {
michael@0 544 CHECK_WRITING_MODE(aWritingMode);
michael@0 545 return mSize.height;
michael@0 546 }
michael@0 547
michael@0 548 nscoord Width(WritingMode aWritingMode) const
michael@0 549 {
michael@0 550 CHECK_WRITING_MODE(aWritingMode);
michael@0 551 return aWritingMode.IsVertical() ? BSize() : ISize();
michael@0 552 }
michael@0 553 nscoord Height(WritingMode aWritingMode) const
michael@0 554 {
michael@0 555 CHECK_WRITING_MODE(aWritingMode);
michael@0 556 return aWritingMode.IsVertical() ? ISize() : BSize();
michael@0 557 }
michael@0 558
michael@0 559 /**
michael@0 560 * Writable references to the logical dimensions
michael@0 561 */
michael@0 562 nscoord& ISize(WritingMode aWritingMode) // inline-size
michael@0 563 {
michael@0 564 CHECK_WRITING_MODE(aWritingMode);
michael@0 565 return mSize.width;
michael@0 566 }
michael@0 567 nscoord& BSize(WritingMode aWritingMode) // block-size
michael@0 568 {
michael@0 569 CHECK_WRITING_MODE(aWritingMode);
michael@0 570 return mSize.height;
michael@0 571 }
michael@0 572
michael@0 573 /**
michael@0 574 * Setters for the physical dimensions
michael@0 575 */
michael@0 576 void SetWidth(WritingMode aWritingMode, nscoord aWidth)
michael@0 577 {
michael@0 578 CHECK_WRITING_MODE(aWritingMode);
michael@0 579 if (aWritingMode.IsVertical()) {
michael@0 580 BSize() = aWidth;
michael@0 581 } else {
michael@0 582 ISize() = aWidth;
michael@0 583 }
michael@0 584 }
michael@0 585 void SetHeight(WritingMode aWritingMode, nscoord aHeight)
michael@0 586 {
michael@0 587 CHECK_WRITING_MODE(aWritingMode);
michael@0 588 if (aWritingMode.IsVertical()) {
michael@0 589 ISize() = aHeight;
michael@0 590 } else {
michael@0 591 BSize() = aHeight;
michael@0 592 }
michael@0 593 }
michael@0 594
michael@0 595 /**
michael@0 596 * Return an nsSize containing our physical dimensions
michael@0 597 */
michael@0 598 nsSize GetPhysicalSize(WritingMode aWritingMode) const
michael@0 599 {
michael@0 600 CHECK_WRITING_MODE(aWritingMode);
michael@0 601 return aWritingMode.IsVertical() ?
michael@0 602 nsSize(BSize(), ISize()) : nsSize(ISize(), BSize());
michael@0 603 }
michael@0 604
michael@0 605 /**
michael@0 606 * Return a LogicalSize representing this size in a different writing mode
michael@0 607 */
michael@0 608 LogicalSize ConvertTo(WritingMode aToMode, WritingMode aFromMode) const
michael@0 609 {
michael@0 610 CHECK_WRITING_MODE(aFromMode);
michael@0 611 return aToMode == aFromMode ?
michael@0 612 *this : LogicalSize(aToMode, GetPhysicalSize(aFromMode));
michael@0 613 }
michael@0 614
michael@0 615 private:
michael@0 616 friend class LogicalRect;
michael@0 617
michael@0 618 LogicalSize() MOZ_DELETE;
michael@0 619
michael@0 620 #ifdef DEBUG
michael@0 621 WritingMode GetWritingMode() const { return mWritingMode; }
michael@0 622 #else
michael@0 623 WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
michael@0 624 #endif
michael@0 625
michael@0 626 nscoord ISize() const // inline-size
michael@0 627 {
michael@0 628 return mSize.width;
michael@0 629 }
michael@0 630 nscoord BSize() const // block-size
michael@0 631 {
michael@0 632 return mSize.height;
michael@0 633 }
michael@0 634
michael@0 635 nscoord& ISize() // inline-size
michael@0 636 {
michael@0 637 return mSize.width;
michael@0 638 }
michael@0 639 nscoord& BSize() // block-size
michael@0 640 {
michael@0 641 return mSize.height;
michael@0 642 }
michael@0 643
michael@0 644 WritingMode mWritingMode;
michael@0 645 nsSize mSize;
michael@0 646 };
michael@0 647
michael@0 648 /**
michael@0 649 * Flow-relative margin
michael@0 650 */
michael@0 651 class LogicalMargin {
michael@0 652 public:
michael@0 653 LogicalMargin(WritingMode aWritingMode)
michael@0 654 :
michael@0 655 #ifdef DEBUG
michael@0 656 mWritingMode(aWritingMode),
michael@0 657 #endif
michael@0 658 mMargin(0, 0, 0, 0)
michael@0 659 { }
michael@0 660
michael@0 661 LogicalMargin(WritingMode aWritingMode,
michael@0 662 nscoord aBStart, nscoord aIEnd,
michael@0 663 nscoord aBEnd, nscoord aIStart)
michael@0 664 :
michael@0 665 #ifdef DEBUG
michael@0 666 mWritingMode(aWritingMode),
michael@0 667 #endif
michael@0 668 mMargin(aBStart, aIEnd, aBEnd, aIStart)
michael@0 669 { }
michael@0 670
michael@0 671 LogicalMargin(WritingMode aWritingMode, const nsMargin& aPhysicalMargin)
michael@0 672 #ifdef DEBUG
michael@0 673 : mWritingMode(aWritingMode)
michael@0 674 #endif
michael@0 675 {
michael@0 676 if (aWritingMode.IsVertical()) {
michael@0 677 if (aWritingMode.IsVerticalLR()) {
michael@0 678 mMargin.top = aPhysicalMargin.left;
michael@0 679 mMargin.bottom = aPhysicalMargin.right;
michael@0 680 } else {
michael@0 681 mMargin.top = aPhysicalMargin.right;
michael@0 682 mMargin.bottom = aPhysicalMargin.left;
michael@0 683 }
michael@0 684 if (aWritingMode.IsBidiLTR()) {
michael@0 685 mMargin.left = aPhysicalMargin.top;
michael@0 686 mMargin.right = aPhysicalMargin.bottom;
michael@0 687 } else {
michael@0 688 mMargin.left = aPhysicalMargin.bottom;
michael@0 689 mMargin.right = aPhysicalMargin.top;
michael@0 690 }
michael@0 691 } else {
michael@0 692 mMargin.top = aPhysicalMargin.top;
michael@0 693 mMargin.bottom = aPhysicalMargin.bottom;
michael@0 694 if (aWritingMode.IsBidiLTR()) {
michael@0 695 mMargin.left = aPhysicalMargin.left;
michael@0 696 mMargin.right = aPhysicalMargin.right;
michael@0 697 } else {
michael@0 698 mMargin.left = aPhysicalMargin.right;
michael@0 699 mMargin.right = aPhysicalMargin.left;
michael@0 700 }
michael@0 701 }
michael@0 702 }
michael@0 703
michael@0 704 nscoord IStart(WritingMode aWritingMode) const // inline-start margin
michael@0 705 {
michael@0 706 CHECK_WRITING_MODE(aWritingMode);
michael@0 707 return mMargin.left;
michael@0 708 }
michael@0 709 nscoord IEnd(WritingMode aWritingMode) const // inline-end margin
michael@0 710 {
michael@0 711 CHECK_WRITING_MODE(aWritingMode);
michael@0 712 return mMargin.right;
michael@0 713 }
michael@0 714 nscoord BStart(WritingMode aWritingMode) const // block-start margin
michael@0 715 {
michael@0 716 CHECK_WRITING_MODE(aWritingMode);
michael@0 717 return mMargin.top;
michael@0 718 }
michael@0 719 nscoord BEnd(WritingMode aWritingMode) const // block-end margin
michael@0 720 {
michael@0 721 CHECK_WRITING_MODE(aWritingMode);
michael@0 722 return mMargin.bottom;
michael@0 723 }
michael@0 724
michael@0 725 nscoord& IStart(WritingMode aWritingMode) // inline-start margin
michael@0 726 {
michael@0 727 CHECK_WRITING_MODE(aWritingMode);
michael@0 728 return mMargin.left;
michael@0 729 }
michael@0 730 nscoord& IEnd(WritingMode aWritingMode) // inline-end margin
michael@0 731 {
michael@0 732 CHECK_WRITING_MODE(aWritingMode);
michael@0 733 return mMargin.right;
michael@0 734 }
michael@0 735 nscoord& BStart(WritingMode aWritingMode) // block-start margin
michael@0 736 {
michael@0 737 CHECK_WRITING_MODE(aWritingMode);
michael@0 738 return mMargin.top;
michael@0 739 }
michael@0 740 nscoord& BEnd(WritingMode aWritingMode) // block-end margin
michael@0 741 {
michael@0 742 CHECK_WRITING_MODE(aWritingMode);
michael@0 743 return mMargin.bottom;
michael@0 744 }
michael@0 745
michael@0 746 nscoord IStartEnd(WritingMode aWritingMode) const // inline margins
michael@0 747 {
michael@0 748 CHECK_WRITING_MODE(aWritingMode);
michael@0 749 return mMargin.LeftRight();
michael@0 750 }
michael@0 751 nscoord BStartEnd(WritingMode aWritingMode) const // block margins
michael@0 752 {
michael@0 753 CHECK_WRITING_MODE(aWritingMode);
michael@0 754 return mMargin.TopBottom();
michael@0 755 }
michael@0 756
michael@0 757 /**
michael@0 758 * Accessors for physical margins, using our writing mode to convert from
michael@0 759 * logical values.
michael@0 760 */
michael@0 761 nscoord Top(WritingMode aWritingMode) const
michael@0 762 {
michael@0 763 CHECK_WRITING_MODE(aWritingMode);
michael@0 764 return aWritingMode.IsVertical() ?
michael@0 765 (aWritingMode.IsBidiLTR() ? IStart() : IEnd()) : BStart();
michael@0 766 }
michael@0 767
michael@0 768 nscoord Bottom(WritingMode aWritingMode) const
michael@0 769 {
michael@0 770 CHECK_WRITING_MODE(aWritingMode);
michael@0 771 return aWritingMode.IsVertical() ?
michael@0 772 (aWritingMode.IsBidiLTR() ? IEnd() : IStart()) : BEnd();
michael@0 773 }
michael@0 774
michael@0 775 nscoord Left(WritingMode aWritingMode) const
michael@0 776 {
michael@0 777 CHECK_WRITING_MODE(aWritingMode);
michael@0 778 return aWritingMode.IsVertical() ?
michael@0 779 (aWritingMode.IsVerticalLR() ? BStart() : BEnd()) :
michael@0 780 (aWritingMode.IsBidiLTR() ? IStart() : IEnd());
michael@0 781 }
michael@0 782
michael@0 783 nscoord Right(WritingMode aWritingMode) const
michael@0 784 {
michael@0 785 CHECK_WRITING_MODE(aWritingMode);
michael@0 786 return aWritingMode.IsVertical() ?
michael@0 787 (aWritingMode.IsVerticalLR() ? BEnd() : BStart()) :
michael@0 788 (aWritingMode.IsBidiLTR() ? IEnd() : IStart());
michael@0 789 }
michael@0 790
michael@0 791 nscoord LeftRight(WritingMode aWritingMode) const
michael@0 792 {
michael@0 793 CHECK_WRITING_MODE(aWritingMode);
michael@0 794 return aWritingMode.IsVertical() ? BStartEnd() : IStartEnd();
michael@0 795 }
michael@0 796
michael@0 797 nscoord TopBottom(WritingMode aWritingMode) const
michael@0 798 {
michael@0 799 CHECK_WRITING_MODE(aWritingMode);
michael@0 800 return aWritingMode.IsVertical() ? IStartEnd() : BStartEnd();
michael@0 801 }
michael@0 802
michael@0 803 void SizeTo(WritingMode aWritingMode,
michael@0 804 nscoord aBStart, nscoord aIEnd, nscoord aBEnd, nscoord aIStart)
michael@0 805 {
michael@0 806 CHECK_WRITING_MODE(aWritingMode);
michael@0 807 mMargin.SizeTo(aBStart, aIEnd, aBEnd, aIStart);
michael@0 808 }
michael@0 809
michael@0 810 /**
michael@0 811 * Return an nsMargin containing our physical coordinates
michael@0 812 */
michael@0 813 nsMargin GetPhysicalMargin(WritingMode aWritingMode) const
michael@0 814 {
michael@0 815 CHECK_WRITING_MODE(aWritingMode);
michael@0 816 return aWritingMode.IsVertical() ?
michael@0 817 (aWritingMode.IsVerticalLR() ?
michael@0 818 nsMargin(IStart(), BEnd(), IEnd(), BStart()) :
michael@0 819 nsMargin(IStart(), BStart(), IEnd(), BEnd())) :
michael@0 820 (aWritingMode.IsBidiLTR() ?
michael@0 821 nsMargin(BStart(), IEnd(), BEnd(), IStart()) :
michael@0 822 nsMargin(BStart(), IStart(), BEnd(), IEnd()));
michael@0 823 }
michael@0 824
michael@0 825 /**
michael@0 826 * Return a LogicalMargin representing this margin in a different
michael@0 827 * writing mode
michael@0 828 */
michael@0 829 LogicalMargin ConvertTo(WritingMode aToMode, WritingMode aFromMode) const
michael@0 830 {
michael@0 831 CHECK_WRITING_MODE(aFromMode);
michael@0 832 return aToMode == aFromMode ?
michael@0 833 *this : LogicalMargin(aToMode, GetPhysicalMargin(aFromMode));
michael@0 834 }
michael@0 835
michael@0 836 bool IsEmpty() const
michael@0 837 {
michael@0 838 return (mMargin.left == 0 && mMargin.top == 0 &&
michael@0 839 mMargin.right == 0 && mMargin.bottom == 0);
michael@0 840 }
michael@0 841
michael@0 842 LogicalMargin operator+(const LogicalMargin& aMargin) {
michael@0 843 CHECK_WRITING_MODE(aMargin.GetWritingMode());
michael@0 844 return LogicalMargin(GetWritingMode(),
michael@0 845 BStart() + aMargin.BStart(),
michael@0 846 IEnd() + aMargin.IEnd(),
michael@0 847 BEnd() + aMargin.BEnd(),
michael@0 848 IStart() + aMargin.IStart());
michael@0 849 }
michael@0 850
michael@0 851 LogicalMargin operator-(const LogicalMargin& aMargin) {
michael@0 852 CHECK_WRITING_MODE(aMargin.GetWritingMode());
michael@0 853 return LogicalMargin(GetWritingMode(),
michael@0 854 BStart() - aMargin.BStart(),
michael@0 855 IEnd() - aMargin.IEnd(),
michael@0 856 BEnd() - aMargin.BEnd(),
michael@0 857 IStart() - aMargin.IStart());
michael@0 858 }
michael@0 859
michael@0 860 private:
michael@0 861 friend class LogicalRect;
michael@0 862
michael@0 863 LogicalMargin() MOZ_DELETE;
michael@0 864
michael@0 865 #ifdef DEBUG
michael@0 866 WritingMode GetWritingMode() const { return mWritingMode; }
michael@0 867 #else
michael@0 868 WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
michael@0 869 #endif
michael@0 870
michael@0 871 nscoord IStart() const // inline-start margin
michael@0 872 {
michael@0 873 return mMargin.left;
michael@0 874 }
michael@0 875 nscoord IEnd() const // inline-end margin
michael@0 876 {
michael@0 877 return mMargin.right;
michael@0 878 }
michael@0 879 nscoord BStart() const // block-start margin
michael@0 880 {
michael@0 881 return mMargin.top;
michael@0 882 }
michael@0 883 nscoord BEnd() const // block-end margin
michael@0 884 {
michael@0 885 return mMargin.bottom;
michael@0 886 }
michael@0 887
michael@0 888 nscoord& IStart() // inline-start margin
michael@0 889 {
michael@0 890 return mMargin.left;
michael@0 891 }
michael@0 892 nscoord& IEnd() // inline-end margin
michael@0 893 {
michael@0 894 return mMargin.right;
michael@0 895 }
michael@0 896 nscoord& BStart() // block-start margin
michael@0 897 {
michael@0 898 return mMargin.top;
michael@0 899 }
michael@0 900 nscoord& BEnd() // block-end margin
michael@0 901 {
michael@0 902 return mMargin.bottom;
michael@0 903 }
michael@0 904
michael@0 905 nscoord IStartEnd() const // inline margins
michael@0 906 {
michael@0 907 return mMargin.LeftRight();
michael@0 908 }
michael@0 909 nscoord BStartEnd() const // block margins
michael@0 910 {
michael@0 911 return mMargin.TopBottom();
michael@0 912 }
michael@0 913
michael@0 914 WritingMode mWritingMode;
michael@0 915 nsMargin mMargin;
michael@0 916 };
michael@0 917
michael@0 918 /**
michael@0 919 * Flow-relative rectangle
michael@0 920 */
michael@0 921 class LogicalRect {
michael@0 922 public:
michael@0 923 LogicalRect(WritingMode aWritingMode)
michael@0 924 :
michael@0 925 #ifdef DEBUG
michael@0 926 mWritingMode(aWritingMode),
michael@0 927 #endif
michael@0 928 mRect(0, 0, 0, 0)
michael@0 929 { }
michael@0 930
michael@0 931 LogicalRect(WritingMode aWritingMode,
michael@0 932 nscoord aIStart, nscoord aBStart,
michael@0 933 nscoord aISize, nscoord aBSize)
michael@0 934 :
michael@0 935 #ifdef DEBUG
michael@0 936 mWritingMode(aWritingMode),
michael@0 937 #endif
michael@0 938 mRect(aIStart, aBStart, aISize, aBSize)
michael@0 939 { }
michael@0 940
michael@0 941 LogicalRect(WritingMode aWritingMode,
michael@0 942 const LogicalPoint& aOrigin,
michael@0 943 const LogicalSize& aSize)
michael@0 944 :
michael@0 945 #ifdef DEBUG
michael@0 946 mWritingMode(aWritingMode),
michael@0 947 #endif
michael@0 948 mRect(aOrigin.mPoint, aSize.mSize)
michael@0 949 {
michael@0 950 CHECK_WRITING_MODE(aOrigin.GetWritingMode());
michael@0 951 CHECK_WRITING_MODE(aSize.GetWritingMode());
michael@0 952 }
michael@0 953
michael@0 954 LogicalRect(WritingMode aWritingMode,
michael@0 955 const nsRect& aRect,
michael@0 956 nscoord aContainerWidth)
michael@0 957 #ifdef DEBUG
michael@0 958 : mWritingMode(aWritingMode)
michael@0 959 #endif
michael@0 960 {
michael@0 961 if (aWritingMode.IsVertical()) {
michael@0 962 if (aWritingMode.IsVerticalLR()) {
michael@0 963 mRect.y = aRect.x;
michael@0 964 } else {
michael@0 965 mRect.y = aContainerWidth - aRect.XMost();
michael@0 966 }
michael@0 967 mRect.height = aRect.width;
michael@0 968 mRect.x = aRect.y;
michael@0 969 mRect.width = aRect.height;
michael@0 970 } else {
michael@0 971 if (aWritingMode.IsBidiLTR()) {
michael@0 972 mRect.x = aRect.x;
michael@0 973 } else {
michael@0 974 mRect.x = aContainerWidth - aRect.XMost();
michael@0 975 }
michael@0 976 mRect.width = aRect.width;
michael@0 977 mRect.y = aRect.y;
michael@0 978 mRect.height = aRect.height;
michael@0 979 }
michael@0 980 }
michael@0 981
michael@0 982 /**
michael@0 983 * Inline- and block-dimension geometry.
michael@0 984 */
michael@0 985 nscoord IStart(WritingMode aWritingMode) const // inline-start edge
michael@0 986 {
michael@0 987 CHECK_WRITING_MODE(aWritingMode);
michael@0 988 return mRect.X();
michael@0 989 }
michael@0 990 nscoord IEnd(WritingMode aWritingMode) const // inline-end edge
michael@0 991 {
michael@0 992 CHECK_WRITING_MODE(aWritingMode);
michael@0 993 return mRect.XMost();
michael@0 994 }
michael@0 995 nscoord ISize(WritingMode aWritingMode) const // inline-size
michael@0 996 {
michael@0 997 CHECK_WRITING_MODE(aWritingMode);
michael@0 998 return mRect.Width();
michael@0 999 }
michael@0 1000
michael@0 1001 nscoord BStart(WritingMode aWritingMode) const // block-start edge
michael@0 1002 {
michael@0 1003 CHECK_WRITING_MODE(aWritingMode);
michael@0 1004 return mRect.Y();
michael@0 1005 }
michael@0 1006 nscoord BEnd(WritingMode aWritingMode) const // block-end edge
michael@0 1007 {
michael@0 1008 CHECK_WRITING_MODE(aWritingMode);
michael@0 1009 return mRect.YMost();
michael@0 1010 }
michael@0 1011 nscoord BSize(WritingMode aWritingMode) const // block-size
michael@0 1012 {
michael@0 1013 CHECK_WRITING_MODE(aWritingMode);
michael@0 1014 return mRect.Height();
michael@0 1015 }
michael@0 1016
michael@0 1017 /**
michael@0 1018 * Writable (reference) accessors are only available for the basic logical
michael@0 1019 * fields (Start and Size), not derivatives like End.
michael@0 1020 */
michael@0 1021 nscoord& IStart(WritingMode aWritingMode) // inline-start edge
michael@0 1022 {
michael@0 1023 CHECK_WRITING_MODE(aWritingMode);
michael@0 1024 return mRect.x;
michael@0 1025 }
michael@0 1026 nscoord& ISize(WritingMode aWritingMode) // inline-size
michael@0 1027 {
michael@0 1028 CHECK_WRITING_MODE(aWritingMode);
michael@0 1029 return mRect.width;
michael@0 1030 }
michael@0 1031 nscoord& BStart(WritingMode aWritingMode) // block-start edge
michael@0 1032 {
michael@0 1033 CHECK_WRITING_MODE(aWritingMode);
michael@0 1034 return mRect.y;
michael@0 1035 }
michael@0 1036 nscoord& BSize(WritingMode aWritingMode) // block-size
michael@0 1037 {
michael@0 1038 CHECK_WRITING_MODE(aWritingMode);
michael@0 1039 return mRect.height;
michael@0 1040 }
michael@0 1041
michael@0 1042 /**
michael@0 1043 * Physical coordinates of the rect.
michael@0 1044 */
michael@0 1045 nscoord X(WritingMode aWritingMode, nscoord aContainerWidth) const
michael@0 1046 {
michael@0 1047 CHECK_WRITING_MODE(aWritingMode);
michael@0 1048 if (aWritingMode.IsVertical()) {
michael@0 1049 return aWritingMode.IsVerticalLR() ?
michael@0 1050 mRect.Y() : aContainerWidth - mRect.YMost();
michael@0 1051 } else {
michael@0 1052 return aWritingMode.IsBidiLTR() ?
michael@0 1053 mRect.X() : aContainerWidth - mRect.XMost();
michael@0 1054 }
michael@0 1055 }
michael@0 1056
michael@0 1057 void SetX(WritingMode aWritingMode, nscoord aX, nscoord aContainerWidth)
michael@0 1058 {
michael@0 1059 CHECK_WRITING_MODE(aWritingMode);
michael@0 1060 if (aWritingMode.IsVertical()) {
michael@0 1061 if (aWritingMode.IsVerticalLR()) {
michael@0 1062 BStart() = aX;
michael@0 1063 } else {
michael@0 1064 BStart() = aContainerWidth - aX - BSize();
michael@0 1065 }
michael@0 1066 } else {
michael@0 1067 if (aWritingMode.IsBidiLTR()) {
michael@0 1068 IStart() = aX;
michael@0 1069 } else {
michael@0 1070 IStart() = aContainerWidth - aX - ISize();
michael@0 1071 }
michael@0 1072 }
michael@0 1073 }
michael@0 1074
michael@0 1075 nscoord Y(WritingMode aWritingMode) const
michael@0 1076 {
michael@0 1077 CHECK_WRITING_MODE(aWritingMode);
michael@0 1078 return aWritingMode.IsVertical() ? mRect.X() : mRect.Y();
michael@0 1079 }
michael@0 1080
michael@0 1081 void SetY(WritingMode aWritingMode, nscoord aY)
michael@0 1082 {
michael@0 1083 CHECK_WRITING_MODE(aWritingMode);
michael@0 1084 if (aWritingMode.IsVertical()) {
michael@0 1085 IStart() = aY;
michael@0 1086 } else {
michael@0 1087 BStart() = aY;
michael@0 1088 }
michael@0 1089 }
michael@0 1090
michael@0 1091 nscoord Width(WritingMode aWritingMode) const
michael@0 1092 {
michael@0 1093 CHECK_WRITING_MODE(aWritingMode);
michael@0 1094 return aWritingMode.IsVertical() ? mRect.Height() : mRect.Width();
michael@0 1095 }
michael@0 1096
michael@0 1097 // When setting the Width of a rect, we keep its physical X-coord fixed
michael@0 1098 // and modify XMax. This means that in the RTL case, we'll be moving
michael@0 1099 // the IStart, so that IEnd remains constant.
michael@0 1100 void SetWidth(WritingMode aWritingMode, nscoord aWidth)
michael@0 1101 {
michael@0 1102 CHECK_WRITING_MODE(aWritingMode);
michael@0 1103 if (aWritingMode.IsVertical()) {
michael@0 1104 if (!aWritingMode.IsVerticalLR()) {
michael@0 1105 BStart() = BStart() + BSize() - aWidth;
michael@0 1106 }
michael@0 1107 BSize() = aWidth;
michael@0 1108 } else {
michael@0 1109 if (!aWritingMode.IsBidiLTR()) {
michael@0 1110 IStart() = IStart() + ISize() - aWidth;
michael@0 1111 }
michael@0 1112 ISize() = aWidth;
michael@0 1113 }
michael@0 1114 }
michael@0 1115
michael@0 1116 nscoord Height(WritingMode aWritingMode) const
michael@0 1117 {
michael@0 1118 CHECK_WRITING_MODE(aWritingMode);
michael@0 1119 return aWritingMode.IsVertical() ? mRect.Width() : mRect.Height();
michael@0 1120 }
michael@0 1121
michael@0 1122 void SetHeight(WritingMode aWritingMode, nscoord aHeight)
michael@0 1123 {
michael@0 1124 CHECK_WRITING_MODE(aWritingMode);
michael@0 1125 if (aWritingMode.IsVertical()) {
michael@0 1126 ISize() = aHeight;
michael@0 1127 } else {
michael@0 1128 BSize() = aHeight;
michael@0 1129 }
michael@0 1130 }
michael@0 1131
michael@0 1132 nscoord XMost(WritingMode aWritingMode, nscoord aContainerWidth) const
michael@0 1133 {
michael@0 1134 CHECK_WRITING_MODE(aWritingMode);
michael@0 1135 if (aWritingMode.IsVertical()) {
michael@0 1136 return aWritingMode.IsVerticalLR() ?
michael@0 1137 mRect.YMost() : aContainerWidth - mRect.Y();
michael@0 1138 } else {
michael@0 1139 return aWritingMode.IsBidiLTR() ?
michael@0 1140 mRect.XMost() : aContainerWidth - mRect.X();
michael@0 1141 }
michael@0 1142 }
michael@0 1143
michael@0 1144 nscoord YMost(WritingMode aWritingMode) const
michael@0 1145 {
michael@0 1146 CHECK_WRITING_MODE(aWritingMode);
michael@0 1147 return aWritingMode.IsVertical() ? mRect.XMost() : mRect.YMost();
michael@0 1148 }
michael@0 1149
michael@0 1150 bool IsEmpty() const
michael@0 1151 {
michael@0 1152 return (mRect.x == 0 && mRect.y == 0 &&
michael@0 1153 mRect.width == 0 && mRect.height == 0);
michael@0 1154 }
michael@0 1155
michael@0 1156 bool IsZeroSize() const
michael@0 1157 {
michael@0 1158 return (mRect.width == 0 && mRect.height == 0);
michael@0 1159 }
michael@0 1160
michael@0 1161 /* XXX are these correct?
michael@0 1162 nscoord ILeft(WritingMode aWritingMode) const
michael@0 1163 {
michael@0 1164 CHECK_WRITING_MODE(aWritingMode);
michael@0 1165 return aWritingMode.IsBidiLTR() ? IStart() : IEnd();
michael@0 1166 }
michael@0 1167 nscoord IRight(WritingMode aWritingMode) const
michael@0 1168 {
michael@0 1169 CHECK_WRITING_MODE(aWritingMode);
michael@0 1170 return aWritingMode.IsBidiLTR() ? IEnd() : IStart();
michael@0 1171 }
michael@0 1172 */
michael@0 1173
michael@0 1174 LogicalPoint Origin(WritingMode aWritingMode) const
michael@0 1175 {
michael@0 1176 CHECK_WRITING_MODE(aWritingMode);
michael@0 1177 return LogicalPoint(aWritingMode, IStart(), BStart());
michael@0 1178 }
michael@0 1179 LogicalSize Size(WritingMode aWritingMode) const
michael@0 1180 {
michael@0 1181 CHECK_WRITING_MODE(aWritingMode);
michael@0 1182 return LogicalSize(aWritingMode, ISize(), BSize());
michael@0 1183 }
michael@0 1184
michael@0 1185 LogicalRect operator+(const LogicalPoint& aPoint) const
michael@0 1186 {
michael@0 1187 CHECK_WRITING_MODE(aPoint.GetWritingMode());
michael@0 1188 return LogicalRect(GetWritingMode(),
michael@0 1189 IStart() + aPoint.I(), BStart() + aPoint.B(),
michael@0 1190 ISize(), BSize());
michael@0 1191 }
michael@0 1192
michael@0 1193 LogicalRect& operator+=(const LogicalPoint& aPoint)
michael@0 1194 {
michael@0 1195 CHECK_WRITING_MODE(aPoint.GetWritingMode());
michael@0 1196 mRect += aPoint.mPoint;
michael@0 1197 return *this;
michael@0 1198 }
michael@0 1199
michael@0 1200 LogicalRect operator-(const LogicalPoint& aPoint) const
michael@0 1201 {
michael@0 1202 CHECK_WRITING_MODE(aPoint.GetWritingMode());
michael@0 1203 return LogicalRect(GetWritingMode(),
michael@0 1204 IStart() - aPoint.I(), BStart() - aPoint.B(),
michael@0 1205 ISize(), BSize());
michael@0 1206 }
michael@0 1207
michael@0 1208 LogicalRect& operator-=(const LogicalPoint& aPoint)
michael@0 1209 {
michael@0 1210 CHECK_WRITING_MODE(aPoint.GetWritingMode());
michael@0 1211 mRect -= aPoint.mPoint;
michael@0 1212 return *this;
michael@0 1213 }
michael@0 1214
michael@0 1215 void MoveBy(WritingMode aWritingMode, const LogicalPoint& aDelta)
michael@0 1216 {
michael@0 1217 CHECK_WRITING_MODE(aWritingMode);
michael@0 1218 CHECK_WRITING_MODE(aDelta.GetWritingMode());
michael@0 1219 IStart() += aDelta.I();
michael@0 1220 BStart() += aDelta.B();
michael@0 1221 }
michael@0 1222
michael@0 1223 void Inflate(nscoord aD) { mRect.Inflate(aD); }
michael@0 1224 void Inflate(nscoord aDI, nscoord aDB) { mRect.Inflate(aDI, aDB); }
michael@0 1225 void Inflate(WritingMode aWritingMode, const LogicalMargin& aMargin)
michael@0 1226 {
michael@0 1227 CHECK_WRITING_MODE(aWritingMode);
michael@0 1228 CHECK_WRITING_MODE(aMargin.GetWritingMode());
michael@0 1229 mRect.Inflate(aMargin.mMargin);
michael@0 1230 }
michael@0 1231
michael@0 1232 void Deflate(nscoord aD) { mRect.Deflate(aD); }
michael@0 1233 void Deflate(nscoord aDI, nscoord aDB) { mRect.Deflate(aDI, aDB); }
michael@0 1234 void Deflate(WritingMode aWritingMode, const LogicalMargin& aMargin)
michael@0 1235 {
michael@0 1236 CHECK_WRITING_MODE(aWritingMode);
michael@0 1237 CHECK_WRITING_MODE(aMargin.GetWritingMode());
michael@0 1238 mRect.Deflate(aMargin.mMargin);
michael@0 1239 }
michael@0 1240
michael@0 1241 /**
michael@0 1242 * Return an nsRect containing our physical coordinates within the given
michael@0 1243 * container width
michael@0 1244 */
michael@0 1245 nsRect GetPhysicalRect(WritingMode aWritingMode,
michael@0 1246 nscoord aContainerWidth) const
michael@0 1247 {
michael@0 1248 CHECK_WRITING_MODE(aWritingMode);
michael@0 1249 if (aWritingMode.IsVertical()) {
michael@0 1250 return nsRect(aWritingMode.IsVerticalLR() ?
michael@0 1251 BStart() : aContainerWidth - BEnd(),
michael@0 1252 IStart(), BSize(), ISize());
michael@0 1253 } else {
michael@0 1254 return nsRect(aWritingMode.IsBidiLTR() ?
michael@0 1255 IStart() : aContainerWidth - IEnd(),
michael@0 1256 BStart(), ISize(), BSize());
michael@0 1257 }
michael@0 1258 }
michael@0 1259
michael@0 1260 #if 0 // XXX this would require aContainerWidth as well
michael@0 1261 /**
michael@0 1262 * Return a LogicalRect representing this rect in a different writing mode
michael@0 1263 */
michael@0 1264 LogicalRect ConvertTo(WritingMode aToMode, WritingMode aFromMode) const
michael@0 1265 {
michael@0 1266 CHECK_WRITING_MODE(aFromMode);
michael@0 1267 return aToMode == aFromMode ?
michael@0 1268 *this : LogicalRect(aToMode, GetPhysicalRect(aFromMode));
michael@0 1269 }
michael@0 1270 #endif
michael@0 1271
michael@0 1272 private:
michael@0 1273 LogicalRect() MOZ_DELETE;
michael@0 1274
michael@0 1275 #ifdef DEBUG
michael@0 1276 WritingMode GetWritingMode() const { return mWritingMode; }
michael@0 1277 #else
michael@0 1278 WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
michael@0 1279 #endif
michael@0 1280
michael@0 1281 nscoord IStart() const // inline-start edge
michael@0 1282 {
michael@0 1283 return mRect.X();
michael@0 1284 }
michael@0 1285 nscoord IEnd() const // inline-end edge
michael@0 1286 {
michael@0 1287 return mRect.XMost();
michael@0 1288 }
michael@0 1289 nscoord ISize() const // inline-size
michael@0 1290 {
michael@0 1291 return mRect.Width();
michael@0 1292 }
michael@0 1293
michael@0 1294 nscoord BStart() const // block-start edge
michael@0 1295 {
michael@0 1296 return mRect.Y();
michael@0 1297 }
michael@0 1298 nscoord BEnd() const // block-end edge
michael@0 1299 {
michael@0 1300 return mRect.YMost();
michael@0 1301 }
michael@0 1302 nscoord BSize() const // block-size
michael@0 1303 {
michael@0 1304 return mRect.Height();
michael@0 1305 }
michael@0 1306
michael@0 1307 nscoord& IStart() // inline-start edge
michael@0 1308 {
michael@0 1309 return mRect.x;
michael@0 1310 }
michael@0 1311 nscoord& ISize() // inline-size
michael@0 1312 {
michael@0 1313 return mRect.width;
michael@0 1314 }
michael@0 1315 nscoord& BStart() // block-start edge
michael@0 1316 {
michael@0 1317 return mRect.y;
michael@0 1318 }
michael@0 1319 nscoord& BSize() // block-size
michael@0 1320 {
michael@0 1321 return mRect.height;
michael@0 1322 }
michael@0 1323
michael@0 1324 WritingMode mWritingMode;
michael@0 1325 nsRect mRect;
michael@0 1326 };
michael@0 1327
michael@0 1328 } // namespace mozilla
michael@0 1329
michael@0 1330 #endif // WritingModes_h_

mercurial