layout/generic/WritingModes.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/generic/WritingModes.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1330 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifndef WritingModes_h_
    1.10 +#define WritingModes_h_
    1.11 +
    1.12 +#include "nsRect.h"
    1.13 +#include "nsStyleStruct.h"
    1.14 +
    1.15 +// If WRITING_MODE_VERTICAL_ENABLED is defined, we will attempt to support
    1.16 +// the vertical writing-mode values; if it is not defined, then
    1.17 +// WritingMode.IsVertical() will be hard-coded to return false, allowing
    1.18 +// many conditional branches to be optimized away while we're in the process
    1.19 +// of transitioning layout to use writing-mode and logical directions, but
    1.20 +// not yet ready to ship vertical support.
    1.21 +
    1.22 +/* #define WRITING_MODE_VERTICAL_ENABLED 1 */
    1.23 +
    1.24 +// It is the caller's responsibility to operate on logical-coordinate objects
    1.25 +// with matched writing modes. Failure to do so will be a runtime bug; the
    1.26 +// compiler can't catch it, but in debug mode, we'll throw an assertion.
    1.27 +// NOTE that in non-debug builds, a writing mode mismatch error will NOT be
    1.28 +// detected, yet the results will be nonsense (and may lead to further layout
    1.29 +// failures). Therefore, it is important to test (and fuzz-test) writing-mode
    1.30 +// support using debug builds.
    1.31 +
    1.32 +// Methods in logical-coordinate classes that take another logical-coordinate
    1.33 +// object as a parameter should call CHECK_WRITING_MODE on it to verify that
    1.34 +// the writing modes match.
    1.35 +// (In some cases, there are internal (private) methods that don't do this;
    1.36 +// such methods should only be used by other methods that have already checked
    1.37 +// the writing modes.)
    1.38 +
    1.39 +#define CHECK_WRITING_MODE(param) \
    1.40 +   NS_ASSERTION(param == mWritingMode, "writing-mode mismatch")
    1.41 +
    1.42 +/**
    1.43 + * mozilla::WritingMode is an immutable class representing a
    1.44 + * writing mode.
    1.45 + *
    1.46 + * It efficiently stores the writing mode and can rapidly compute
    1.47 + * interesting things about it for use in layout.
    1.48 + *
    1.49 + * Writing modes are computed from the CSS 'direction',
    1.50 + * 'writing-mode', and 'text-orientation' properties.
    1.51 + * See CSS3 Writing Modes for more information
    1.52 + *   http://www.w3.org/TR/css3-writing-modes/
    1.53 + */
    1.54 +
    1.55 +namespace mozilla {
    1.56 +
    1.57 +class WritingMode {
    1.58 +public:
    1.59 +  /**
    1.60 +   * Absolute inline flow direction
    1.61 +   */
    1.62 +  enum InlineDir {
    1.63 +    eInlineLTR = 0x00, // text flows horizontally left to right
    1.64 +    eInlineRTL = 0x02, // text flows horizontally right to left
    1.65 +    eInlineTTB = 0x01, // text flows vertically top to bottom
    1.66 +    eInlineBTT = 0x03, // text flows vertically bottom to top
    1.67 +  };
    1.68 +
    1.69 +  /**
    1.70 +   * Absolute block flow direction
    1.71 +   */
    1.72 +  enum BlockDir {
    1.73 +    eBlockTB = 0x00, // horizontal lines stack top to bottom
    1.74 +    eBlockRL = 0x01, // vertical lines stack right to left
    1.75 +    eBlockLR = 0x05, // vertical lines stack left to right
    1.76 +  };
    1.77 +
    1.78 +  /**
    1.79 +   * Line-relative (bidi-relative) inline flow direction
    1.80 +   */
    1.81 +  enum BidiDir {
    1.82 +    eBidiLTR = 0x00, // inline flow matches bidi LTR text
    1.83 +    eBidiRTL = 0x10, // inline flow matches bidi RTL text
    1.84 +  };
    1.85 +
    1.86 +  /**
    1.87 +   * Unknown writing mode (should never actually be stored or used anywhere).
    1.88 +   */
    1.89 +  enum {
    1.90 +    eUnknownWritingMode = 0xff
    1.91 +  };
    1.92 +
    1.93 +  /**
    1.94 +   * Return the absolute inline flow direction as an InlineDir
    1.95 +   */
    1.96 +  InlineDir GetInlineDir() const { return InlineDir(mWritingMode & eInlineMask); }
    1.97 +
    1.98 +  /**
    1.99 +   * Return the absolute block flow direction as a BlockDir
   1.100 +   */
   1.101 +  BlockDir GetBlockDir() const { return BlockDir(mWritingMode & eBlockMask); }
   1.102 +
   1.103 +  /**
   1.104 +   * Return the line-relative inline flow direction as a BidiDir
   1.105 +   */
   1.106 +  BidiDir GetBidiDir() const { return BidiDir(mWritingMode & eBidiMask); }
   1.107 +
   1.108 +  /**
   1.109 +   * Return true if LTR. (Convenience method)
   1.110 +   */
   1.111 +  bool IsBidiLTR() const { return eBidiLTR == (mWritingMode & eBidiMask); }
   1.112 +
   1.113 +  /**
   1.114 +   * True if vertical-mode block direction is LR (convenience method).
   1.115 +   */
   1.116 +  bool IsVerticalLR() const { return eBlockLR == (mWritingMode & eBlockMask); }
   1.117 +
   1.118 +  /**
   1.119 +   * True if vertical writing mode, i.e. when
   1.120 +   * writing-mode: vertical-lr | vertical-rl.
   1.121 +   */
   1.122 +#ifdef WRITING_MODE_VERTICAL_ENABLED
   1.123 +  bool IsVertical() const { return !!(mWritingMode & eOrientationMask); }
   1.124 +#else
   1.125 +  bool IsVertical() const { return false; }
   1.126 +#endif
   1.127 +
   1.128 +  /**
   1.129 +   * True if line-over/line-under are inverted from block-start/block-end.
   1.130 +   * This is true when
   1.131 +   *   - writing-mode is vertical-rl && text-orientation is sideways-left
   1.132 +   *   - writing-mode is vertical-lr && text-orientation is not sideways-left
   1.133 +   */
   1.134 +#ifdef WRITING_MODE_VERTICAL_ENABLED
   1.135 +  bool IsLineInverted() const { return !!(mWritingMode & eLineOrientMask); }
   1.136 +#else
   1.137 +  bool IsLineInverted() const { return false; }
   1.138 +#endif
   1.139 +
   1.140 +  /**
   1.141 +   * Block-axis flow-relative to line-relative factor.
   1.142 +   * May be used as a multiplication factor for block-axis coordinates
   1.143 +   * to convert between flow- and line-relative coordinate systems (e.g.
   1.144 +   * positioning an over- or under-line decoration).
   1.145 +   */
   1.146 +  int FlowRelativeToLineRelativeFactor() const
   1.147 +  {
   1.148 +    return IsLineInverted() ? -1 : 1;
   1.149 +  }
   1.150 +
   1.151 +  /**
   1.152 +   * Default constructor gives us a horizontal, LTR writing mode.
   1.153 +   * XXX We will probably eliminate this and require explicit initialization
   1.154 +   *     in all cases once transition is complete.
   1.155 +   */
   1.156 +  WritingMode()
   1.157 +    : mWritingMode(0)
   1.158 +  { }
   1.159 +
   1.160 +  /**
   1.161 +   * Construct writing mode based on a style context
   1.162 +   */
   1.163 +  WritingMode(const nsStyleVisibility* aStyleVisibility)
   1.164 +  {
   1.165 +    NS_ASSERTION(aStyleVisibility, "we need an nsStyleVisibility here");
   1.166 +
   1.167 +#ifdef WRITING_MODE_VERTICAL_ENABLED
   1.168 +    switch (aStyleVisibility->mWritingMode) {
   1.169 +      case NS_STYLE_WRITING_MODE_HORIZONTAL_TB:
   1.170 +        mWritingMode = 0;
   1.171 +        break;
   1.172 +
   1.173 +      case NS_STYLE_WRITING_MODE_VERTICAL_LR:
   1.174 +        mWritingMode = eBlockFlowMask |
   1.175 +                       eLineOrientMask | //XXX needs update when text-orientation added
   1.176 +                       eOrientationMask;
   1.177 +        break;
   1.178 +
   1.179 +      case NS_STYLE_WRITING_MODE_VERTICAL_RL:
   1.180 +        mWritingMode = eOrientationMask;
   1.181 +        break;
   1.182 +
   1.183 +      default:
   1.184 +        NS_NOTREACHED("unknown writing mode!");
   1.185 +        mWritingMode = 0;
   1.186 +        break;
   1.187 +    }
   1.188 +#else
   1.189 +    mWritingMode = 0;
   1.190 +#endif
   1.191 +
   1.192 +    if (NS_STYLE_DIRECTION_RTL == aStyleVisibility->mDirection) {
   1.193 +      mWritingMode |= eInlineFlowMask | //XXX needs update when text-orientation added
   1.194 +                      eBidiMask;
   1.195 +    }
   1.196 +  }
   1.197 +
   1.198 +  // For unicode-bidi: plaintext, reset the direction of the writing mode from
   1.199 +  // the bidi paragraph level of the content
   1.200 +
   1.201 +  //XXX change uint8_t to UBiDiLevel after bug 924851
   1.202 +  void SetDirectionFromBidiLevel(uint8_t level)
   1.203 +  {
   1.204 +    if (level & 1) {
   1.205 +      // odd level, set RTL
   1.206 +      mWritingMode |= eBidiMask;
   1.207 +    } else {
   1.208 +      // even level, set LTR
   1.209 +      mWritingMode &= ~eBidiMask;
   1.210 +    }
   1.211 +  }
   1.212 +
   1.213 +  /**
   1.214 +   * Compare two WritingModes for equality.
   1.215 +   */
   1.216 +  bool operator==(const WritingMode& aOther) const
   1.217 +  {
   1.218 +    return mWritingMode == aOther.mWritingMode;
   1.219 +  }
   1.220 +
   1.221 +private:
   1.222 +  friend class LogicalPoint;
   1.223 +  friend class LogicalSize;
   1.224 +  friend class LogicalMargin;
   1.225 +  friend class LogicalRect;
   1.226 +
   1.227 +  /**
   1.228 +   * Return a WritingMode representing an unknown value.
   1.229 +   */
   1.230 +  static inline WritingMode Unknown()
   1.231 +  {
   1.232 +    return WritingMode(eUnknownWritingMode);
   1.233 +  }
   1.234 +
   1.235 +  /**
   1.236 +   * Constructing a WritingMode with an arbitrary value is a private operation
   1.237 +   * currently only used by the Unknown() static method.
   1.238 +   */
   1.239 +  WritingMode(uint8_t aValue)
   1.240 +    : mWritingMode(aValue)
   1.241 +  { }
   1.242 +
   1.243 +  uint8_t mWritingMode;
   1.244 +
   1.245 +  enum Masks {
   1.246 +    // Masks for our bits; true chosen as opposite of commonest case
   1.247 +    eOrientationMask = 0x01, // true means vertical text
   1.248 +    eInlineFlowMask  = 0x02, // true means absolute RTL/BTT (against physical coords)
   1.249 +    eBlockFlowMask   = 0x04, // true means vertical-LR (or horizontal-BT if added)
   1.250 +    eLineOrientMask  = 0x08, // true means over != block-start
   1.251 +    eBidiMask        = 0x10, // true means line-relative RTL (bidi RTL)
   1.252 +    // Note: We have one excess bit of info; WritingMode can pack into 4 bits.
   1.253 +    // But since we have space, we're caching interesting things for fast access.
   1.254 +
   1.255 +    // Masks for output enums
   1.256 +    eInlineMask = 0x03,
   1.257 +    eBlockMask  = 0x05
   1.258 +  };
   1.259 +};
   1.260 +
   1.261 +
   1.262 +/**
   1.263 + * Logical-coordinate classes:
   1.264 + *
   1.265 + * There are three sets of coordinate space:
   1.266 + *   - physical (top, left, bottom, right)
   1.267 + *       relative to graphics coord system
   1.268 + *   - flow-relative (block-start, inline-start, block-end, inline-end)
   1.269 + *       relative to block/inline flow directions
   1.270 + *   - line-relative (line-over, line-left, line-under, line-right)
   1.271 + *       relative to glyph orientation / inline bidi directions
   1.272 + * See CSS3 Writing Modes for more information
   1.273 + *   http://www.w3.org/TR/css3-writing-modes/#abstract-box
   1.274 + *
   1.275 + * For shorthand, B represents the block-axis
   1.276 + *                I represents the inline-axis
   1.277 + *
   1.278 + * The flow-relative geometric classes store coords in flow-relative space.
   1.279 + * They use a private ns{Point,Size,Rect,Margin} member to store the actual
   1.280 + * coordinate values, but reinterpret them as logical instead of physical.
   1.281 + * This allows us to easily perform calculations in logical space (provided
   1.282 + * writing modes of the operands match), by simply mapping to nsPoint (etc)
   1.283 + * methods.
   1.284 + *
   1.285 + * Physical-coordinate accessors/setters are responsible to translate these
   1.286 + * internal logical values as necessary.
   1.287 + *
   1.288 + * In DEBUG builds, the logical types store their WritingMode and check
   1.289 + * that the same WritingMode is passed whenever callers ask them to do a
   1.290 + * writing-mode-dependent operation. Non-DEBUG builds do NOT check this,
   1.291 + * to avoid the overhead of storing WritingMode fields.
   1.292 + *
   1.293 + * Open question: do we need a different set optimized for line-relative
   1.294 + * math, for use in nsLineLayout and the like? Or is multiplying values
   1.295 + * by FlowRelativeToLineRelativeFactor() enough?
   1.296 + */
   1.297 +
   1.298 +/**
   1.299 + * Flow-relative point
   1.300 + */
   1.301 +class LogicalPoint {
   1.302 +public:
   1.303 +  LogicalPoint(WritingMode aWritingMode)
   1.304 +    :
   1.305 +#ifdef DEBUG
   1.306 +      mWritingMode(aWritingMode),
   1.307 +#endif
   1.308 +      mPoint(0, 0)
   1.309 +  { }
   1.310 +
   1.311 +  // Construct from a writing mode and individual coordinates (which MUST be
   1.312 +  // values in that writing mode, NOT physical coordinates!)
   1.313 +  LogicalPoint(WritingMode aWritingMode, nscoord aI, nscoord aB)
   1.314 +    :
   1.315 +#ifdef DEBUG
   1.316 +      mWritingMode(aWritingMode),
   1.317 +#endif
   1.318 +      mPoint(aI, aB)
   1.319 +  { }
   1.320 +
   1.321 +  // Construct from a writing mode and a physical point, within a given
   1.322 +  // containing rectangle's width (defining the conversion between LTR
   1.323 +  // and RTL coordinates).
   1.324 +  LogicalPoint(WritingMode aWritingMode,
   1.325 +               const nsPoint& aPoint,
   1.326 +               nscoord aContainerWidth)
   1.327 +#ifdef DEBUG
   1.328 +    : mWritingMode(aWritingMode)
   1.329 +#endif
   1.330 +  {
   1.331 +    if (aWritingMode.IsVertical()) {
   1.332 +      I() = aPoint.y;
   1.333 +      B() = aWritingMode.IsVerticalLR() ? aPoint.x : aContainerWidth - aPoint.x;
   1.334 +    } else {
   1.335 +      I() = aWritingMode.IsBidiLTR() ? aPoint.x : aContainerWidth - aPoint.x;
   1.336 +      B() = aPoint.y;
   1.337 +    }
   1.338 +  }
   1.339 +
   1.340 +  /**
   1.341 +   * Read-only (const) access to the coordinates, in both logical
   1.342 +   * and physical terms.
   1.343 +   */
   1.344 +  nscoord I(WritingMode aWritingMode) const // inline-axis
   1.345 +  {
   1.346 +    CHECK_WRITING_MODE(aWritingMode);
   1.347 +    return mPoint.x;
   1.348 +  }
   1.349 +  nscoord B(WritingMode aWritingMode) const // block-axis
   1.350 +  {
   1.351 +    CHECK_WRITING_MODE(aWritingMode);
   1.352 +    return mPoint.y;
   1.353 +  }
   1.354 +
   1.355 +  nscoord X(WritingMode aWritingMode, nscoord aContainerWidth) const
   1.356 +  {
   1.357 +    CHECK_WRITING_MODE(aWritingMode);
   1.358 +    if (aWritingMode.IsVertical()) {
   1.359 +      return aWritingMode.IsVerticalLR() ? B() : aContainerWidth - B();
   1.360 +    } else {
   1.361 +      return aWritingMode.IsBidiLTR() ? I() : aContainerWidth - I();
   1.362 +    }
   1.363 +  }
   1.364 +  nscoord Y(WritingMode aWritingMode) const
   1.365 +  {
   1.366 +    CHECK_WRITING_MODE(aWritingMode);
   1.367 +    return aWritingMode.IsVertical() ? I() : B();
   1.368 +  }
   1.369 +
   1.370 +  /**
   1.371 +   * These non-const accessors return a reference (lvalue) that can be
   1.372 +   * assigned to by callers.
   1.373 +   */
   1.374 +  nscoord& I(WritingMode aWritingMode) // inline-axis
   1.375 +  {
   1.376 +    CHECK_WRITING_MODE(aWritingMode);
   1.377 +    return mPoint.x;
   1.378 +  }
   1.379 +  nscoord& B(WritingMode aWritingMode) // block-axis
   1.380 +  {
   1.381 +    CHECK_WRITING_MODE(aWritingMode);
   1.382 +    return mPoint.y;
   1.383 +  }
   1.384 +
   1.385 +  /**
   1.386 +   * Setters for the physical coordinates.
   1.387 +   */
   1.388 +  void SetX(WritingMode aWritingMode, nscoord aX, nscoord aContainerWidth)
   1.389 +  {
   1.390 +    CHECK_WRITING_MODE(aWritingMode);
   1.391 +    if (aWritingMode.IsVertical()) {
   1.392 +      B() = aWritingMode.IsVerticalLR() ? aX : aContainerWidth - aX;
   1.393 +    } else {
   1.394 +      I() = aWritingMode.IsBidiLTR() ? aX : aContainerWidth - aX;
   1.395 +    }
   1.396 +  }
   1.397 +  void SetY(WritingMode aWritingMode, nscoord aY)
   1.398 +  {
   1.399 +    CHECK_WRITING_MODE(aWritingMode);
   1.400 +    if (aWritingMode.IsVertical()) {
   1.401 +      B() = aY;
   1.402 +    } else {
   1.403 +      I() = aY;
   1.404 +    }
   1.405 +  }
   1.406 +
   1.407 +  /**
   1.408 +   * Return a physical point corresponding to our logical coordinates,
   1.409 +   * converted according to our writing mode.
   1.410 +   */
   1.411 +  nsPoint GetPhysicalPoint(WritingMode aWritingMode,
   1.412 +                           nscoord aContainerWidth) const
   1.413 +  {
   1.414 +    CHECK_WRITING_MODE(aWritingMode);
   1.415 +    if (aWritingMode.IsVertical()) {
   1.416 +      return nsPoint(aWritingMode.IsVerticalLR() ? B() : aContainerWidth - B(),
   1.417 +                     I());
   1.418 +    } else {
   1.419 +      return nsPoint(aWritingMode.IsBidiLTR() ? I() : aContainerWidth - I(),
   1.420 +                     B());
   1.421 +    }
   1.422 +  }
   1.423 +
   1.424 +  /**
   1.425 +   * Return the equivalent point in a different writing mode.
   1.426 +   */
   1.427 +  LogicalPoint ConvertTo(WritingMode aToMode, WritingMode aFromMode,
   1.428 +                         nscoord aContainerWidth) const
   1.429 +  {
   1.430 +    CHECK_WRITING_MODE(aFromMode);
   1.431 +    return aToMode == aFromMode ?
   1.432 +      *this : LogicalPoint(aToMode,
   1.433 +                           GetPhysicalPoint(aFromMode, aContainerWidth),
   1.434 +                           aContainerWidth);
   1.435 +  }
   1.436 +
   1.437 +  LogicalPoint operator+(const LogicalPoint& aOther) const
   1.438 +  {
   1.439 +    CHECK_WRITING_MODE(aOther.GetWritingMode());
   1.440 +    // In non-debug builds, LogicalPoint does not store the WritingMode,
   1.441 +    // so the first parameter here (which will always be eUnknownWritingMode)
   1.442 +    // is ignored.
   1.443 +    return LogicalPoint(GetWritingMode(),
   1.444 +                        mPoint.x + aOther.mPoint.x,
   1.445 +                        mPoint.y + aOther.mPoint.y);
   1.446 +  }
   1.447 +
   1.448 +private:
   1.449 +  friend class LogicalRect;
   1.450 +
   1.451 +  /**
   1.452 +   * NOTE that in non-DEBUG builds, GetWritingMode() always returns
   1.453 +   * eUnknownWritingMode, as the current mode is not stored in the logical-
   1.454 +   * geometry classes. Therefore, this method is private; it is used ONLY
   1.455 +   * by the DEBUG-mode checking macros in this class and its friends;
   1.456 +   * other code is not allowed to ask a logical point for its writing mode,
   1.457 +   * as this info will simply not be available in non-DEBUG builds.
   1.458 +   *
   1.459 +   * Also, in non-DEBUG builds, CHECK_WRITING_MODE does nothing, and the
   1.460 +   * WritingMode parameter to logical methods will generally be optimized
   1.461 +   * away altogether.
   1.462 +   */
   1.463 +#ifdef DEBUG
   1.464 +  WritingMode GetWritingMode() const { return mWritingMode; }
   1.465 +#else
   1.466 +  WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
   1.467 +#endif
   1.468 +
   1.469 +  // We don't allow construction of a LogicalPoint with no writing mode.
   1.470 +  LogicalPoint() MOZ_DELETE;
   1.471 +
   1.472 +  // Accessors that don't take or check a WritingMode value.
   1.473 +  // These are for internal use only; they are called by methods that have
   1.474 +  // themselves already checked the WritingMode passed by the caller.
   1.475 +  nscoord I() const // inline-axis
   1.476 +  {
   1.477 +    return mPoint.x;
   1.478 +  }
   1.479 +  nscoord B() const // block-axis
   1.480 +  {
   1.481 +    return mPoint.y;
   1.482 +  }
   1.483 +
   1.484 +  nscoord& I() // inline-axis
   1.485 +  {
   1.486 +    return mPoint.x;
   1.487 +  }
   1.488 +  nscoord& B() // block-axis
   1.489 +  {
   1.490 +    return mPoint.y;
   1.491 +  }
   1.492 +
   1.493 +  WritingMode mWritingMode;
   1.494 +
   1.495 +  // We use an nsPoint to hold the coordinates, but reinterpret its .x and .y
   1.496 +  // fields as the inline and block directions. Hence, this is not exposed
   1.497 +  // directly, but only through accessors that will map them according to the
   1.498 +  // writing mode.
   1.499 +  nsPoint mPoint;
   1.500 +};
   1.501 +
   1.502 +/**
   1.503 + * Flow-relative size
   1.504 + */
   1.505 +class LogicalSize {
   1.506 +public:
   1.507 +  LogicalSize(WritingMode aWritingMode)
   1.508 +    :
   1.509 +#ifdef DEBUG
   1.510 +      mWritingMode(aWritingMode),
   1.511 +#endif
   1.512 +      mSize(0, 0)
   1.513 +  { }
   1.514 +
   1.515 +  LogicalSize(WritingMode aWritingMode, nscoord aISize, nscoord aBSize)
   1.516 +    :
   1.517 +#ifdef DEBUG
   1.518 +      mWritingMode(aWritingMode),
   1.519 +#endif
   1.520 +      mSize(aISize, aBSize)
   1.521 +  { }
   1.522 +
   1.523 +  LogicalSize(WritingMode aWritingMode, const nsSize& aPhysicalSize)
   1.524 +#ifdef DEBUG
   1.525 +    : mWritingMode(aWritingMode)
   1.526 +#endif
   1.527 +  {
   1.528 +    if (aWritingMode.IsVertical()) {
   1.529 +      ISize() = aPhysicalSize.height;
   1.530 +      BSize() = aPhysicalSize.width;
   1.531 +    } else {
   1.532 +      ISize() = aPhysicalSize.width;
   1.533 +      BSize() = aPhysicalSize.height;
   1.534 +    }
   1.535 +  }
   1.536 +
   1.537 +  /**
   1.538 +   * Dimensions in logical and physical terms
   1.539 +   */
   1.540 +  nscoord ISize(WritingMode aWritingMode) const // inline-size
   1.541 +  {
   1.542 +    CHECK_WRITING_MODE(aWritingMode);
   1.543 +    return mSize.width;
   1.544 +  }
   1.545 +  nscoord BSize(WritingMode aWritingMode) const // block-size
   1.546 +  {
   1.547 +    CHECK_WRITING_MODE(aWritingMode);
   1.548 +    return mSize.height;
   1.549 +  }
   1.550 +
   1.551 +  nscoord Width(WritingMode aWritingMode) const
   1.552 +  {
   1.553 +    CHECK_WRITING_MODE(aWritingMode);
   1.554 +    return aWritingMode.IsVertical() ? BSize() : ISize();
   1.555 +  }
   1.556 +  nscoord Height(WritingMode aWritingMode) const
   1.557 +  {
   1.558 +    CHECK_WRITING_MODE(aWritingMode);
   1.559 +    return aWritingMode.IsVertical() ? ISize() : BSize();
   1.560 +  }
   1.561 +
   1.562 +  /**
   1.563 +   * Writable references to the logical dimensions
   1.564 +   */
   1.565 +  nscoord& ISize(WritingMode aWritingMode) // inline-size
   1.566 +  {
   1.567 +    CHECK_WRITING_MODE(aWritingMode);
   1.568 +    return mSize.width;
   1.569 +  }
   1.570 +  nscoord& BSize(WritingMode aWritingMode) // block-size
   1.571 +  {
   1.572 +    CHECK_WRITING_MODE(aWritingMode);
   1.573 +    return mSize.height;
   1.574 +  }
   1.575 +
   1.576 +  /**
   1.577 +   * Setters for the physical dimensions
   1.578 +   */
   1.579 +  void SetWidth(WritingMode aWritingMode, nscoord aWidth)
   1.580 +  {
   1.581 +    CHECK_WRITING_MODE(aWritingMode);
   1.582 +    if (aWritingMode.IsVertical()) {
   1.583 +      BSize() = aWidth;
   1.584 +    } else {
   1.585 +      ISize() = aWidth;
   1.586 +    }
   1.587 +  }
   1.588 +  void SetHeight(WritingMode aWritingMode, nscoord aHeight)
   1.589 +  {
   1.590 +    CHECK_WRITING_MODE(aWritingMode);
   1.591 +    if (aWritingMode.IsVertical()) {
   1.592 +      ISize() = aHeight;
   1.593 +    } else {
   1.594 +      BSize() = aHeight;
   1.595 +    }
   1.596 +  }
   1.597 +
   1.598 +  /**
   1.599 +   * Return an nsSize containing our physical dimensions
   1.600 +   */
   1.601 +  nsSize GetPhysicalSize(WritingMode aWritingMode) const
   1.602 +  {
   1.603 +    CHECK_WRITING_MODE(aWritingMode);
   1.604 +    return aWritingMode.IsVertical() ?
   1.605 +      nsSize(BSize(), ISize()) : nsSize(ISize(), BSize());
   1.606 +  }
   1.607 +
   1.608 +  /**
   1.609 +   * Return a LogicalSize representing this size in a different writing mode
   1.610 +   */
   1.611 +  LogicalSize ConvertTo(WritingMode aToMode, WritingMode aFromMode) const
   1.612 +  {
   1.613 +    CHECK_WRITING_MODE(aFromMode);
   1.614 +    return aToMode == aFromMode ?
   1.615 +      *this : LogicalSize(aToMode, GetPhysicalSize(aFromMode));
   1.616 +  }
   1.617 +
   1.618 +private:
   1.619 +  friend class LogicalRect;
   1.620 +
   1.621 +  LogicalSize() MOZ_DELETE;
   1.622 +
   1.623 +#ifdef DEBUG
   1.624 +  WritingMode GetWritingMode() const { return mWritingMode; }
   1.625 +#else
   1.626 +  WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
   1.627 +#endif
   1.628 +
   1.629 +  nscoord ISize() const // inline-size
   1.630 +  {
   1.631 +    return mSize.width;
   1.632 +  }
   1.633 +  nscoord BSize() const // block-size
   1.634 +  {
   1.635 +    return mSize.height;
   1.636 +  }
   1.637 +
   1.638 +  nscoord& ISize() // inline-size
   1.639 +  {
   1.640 +    return mSize.width;
   1.641 +  }
   1.642 +  nscoord& BSize() // block-size
   1.643 +  {
   1.644 +    return mSize.height;
   1.645 +  }
   1.646 +
   1.647 +  WritingMode mWritingMode;
   1.648 +  nsSize      mSize;
   1.649 +};
   1.650 +
   1.651 +/**
   1.652 + * Flow-relative margin
   1.653 + */
   1.654 +class LogicalMargin {
   1.655 +public:
   1.656 +  LogicalMargin(WritingMode aWritingMode)
   1.657 +    :
   1.658 +#ifdef DEBUG
   1.659 +      mWritingMode(aWritingMode),
   1.660 +#endif
   1.661 +      mMargin(0, 0, 0, 0)
   1.662 +  { }
   1.663 +
   1.664 +  LogicalMargin(WritingMode aWritingMode,
   1.665 +                nscoord aBStart, nscoord aIEnd,
   1.666 +                nscoord aBEnd, nscoord aIStart)
   1.667 +    :
   1.668 +#ifdef DEBUG
   1.669 +      mWritingMode(aWritingMode),
   1.670 +#endif
   1.671 +      mMargin(aBStart, aIEnd, aBEnd, aIStart)
   1.672 +  { }
   1.673 +
   1.674 +  LogicalMargin(WritingMode aWritingMode, const nsMargin& aPhysicalMargin)
   1.675 +#ifdef DEBUG
   1.676 +    : mWritingMode(aWritingMode)
   1.677 +#endif
   1.678 +  {
   1.679 +    if (aWritingMode.IsVertical()) {
   1.680 +      if (aWritingMode.IsVerticalLR()) {
   1.681 +        mMargin.top = aPhysicalMargin.left;
   1.682 +        mMargin.bottom = aPhysicalMargin.right;
   1.683 +      } else {
   1.684 +        mMargin.top = aPhysicalMargin.right;
   1.685 +        mMargin.bottom = aPhysicalMargin.left;
   1.686 +      }
   1.687 +      if (aWritingMode.IsBidiLTR()) {
   1.688 +        mMargin.left = aPhysicalMargin.top;
   1.689 +        mMargin.right = aPhysicalMargin.bottom;
   1.690 +      } else {
   1.691 +        mMargin.left = aPhysicalMargin.bottom;
   1.692 +        mMargin.right = aPhysicalMargin.top;
   1.693 +      }
   1.694 +    } else {
   1.695 +      mMargin.top = aPhysicalMargin.top;
   1.696 +      mMargin.bottom = aPhysicalMargin.bottom;
   1.697 +      if (aWritingMode.IsBidiLTR()) {
   1.698 +        mMargin.left = aPhysicalMargin.left;
   1.699 +        mMargin.right = aPhysicalMargin.right;
   1.700 +      } else {
   1.701 +        mMargin.left = aPhysicalMargin.right;
   1.702 +        mMargin.right = aPhysicalMargin.left;
   1.703 +      }
   1.704 +    }
   1.705 +  }
   1.706 +
   1.707 +  nscoord IStart(WritingMode aWritingMode) const // inline-start margin
   1.708 +  {
   1.709 +    CHECK_WRITING_MODE(aWritingMode);
   1.710 +    return mMargin.left;
   1.711 +  }
   1.712 +  nscoord IEnd(WritingMode aWritingMode) const // inline-end margin
   1.713 +  {
   1.714 +    CHECK_WRITING_MODE(aWritingMode);
   1.715 +    return mMargin.right;
   1.716 +  }
   1.717 +  nscoord BStart(WritingMode aWritingMode) const // block-start margin
   1.718 +  {
   1.719 +    CHECK_WRITING_MODE(aWritingMode);
   1.720 +    return mMargin.top;
   1.721 +  }
   1.722 +  nscoord BEnd(WritingMode aWritingMode) const // block-end margin
   1.723 +  {
   1.724 +    CHECK_WRITING_MODE(aWritingMode);
   1.725 +    return mMargin.bottom;
   1.726 +  }
   1.727 +
   1.728 +  nscoord& IStart(WritingMode aWritingMode) // inline-start margin
   1.729 +  {
   1.730 +    CHECK_WRITING_MODE(aWritingMode);
   1.731 +    return mMargin.left;
   1.732 +  }
   1.733 +  nscoord& IEnd(WritingMode aWritingMode) // inline-end margin
   1.734 +  {
   1.735 +    CHECK_WRITING_MODE(aWritingMode);
   1.736 +    return mMargin.right;
   1.737 +  }
   1.738 +  nscoord& BStart(WritingMode aWritingMode) // block-start margin
   1.739 +  {
   1.740 +    CHECK_WRITING_MODE(aWritingMode);
   1.741 +    return mMargin.top;
   1.742 +  }
   1.743 +  nscoord& BEnd(WritingMode aWritingMode) // block-end margin
   1.744 +  {
   1.745 +    CHECK_WRITING_MODE(aWritingMode);
   1.746 +    return mMargin.bottom;
   1.747 +  }
   1.748 +
   1.749 +  nscoord IStartEnd(WritingMode aWritingMode) const // inline margins
   1.750 +  {
   1.751 +    CHECK_WRITING_MODE(aWritingMode);
   1.752 +    return mMargin.LeftRight();
   1.753 +  }
   1.754 +  nscoord BStartEnd(WritingMode aWritingMode) const // block margins
   1.755 +  {
   1.756 +    CHECK_WRITING_MODE(aWritingMode);
   1.757 +    return mMargin.TopBottom();
   1.758 +  }
   1.759 +
   1.760 +  /**
   1.761 +   * Accessors for physical margins, using our writing mode to convert from
   1.762 +   * logical values.
   1.763 +   */
   1.764 +  nscoord Top(WritingMode aWritingMode) const
   1.765 +  {
   1.766 +    CHECK_WRITING_MODE(aWritingMode);
   1.767 +    return aWritingMode.IsVertical() ?
   1.768 +      (aWritingMode.IsBidiLTR() ? IStart() : IEnd()) : BStart();
   1.769 +  }
   1.770 +
   1.771 +  nscoord Bottom(WritingMode aWritingMode) const
   1.772 +  {
   1.773 +    CHECK_WRITING_MODE(aWritingMode);
   1.774 +    return aWritingMode.IsVertical() ?
   1.775 +      (aWritingMode.IsBidiLTR() ? IEnd() : IStart()) : BEnd();
   1.776 +  }
   1.777 +
   1.778 +  nscoord Left(WritingMode aWritingMode) const
   1.779 +  {
   1.780 +    CHECK_WRITING_MODE(aWritingMode);
   1.781 +    return aWritingMode.IsVertical() ?
   1.782 +      (aWritingMode.IsVerticalLR() ? BStart() : BEnd()) :
   1.783 +      (aWritingMode.IsBidiLTR() ? IStart() : IEnd());
   1.784 +  }
   1.785 +
   1.786 +  nscoord Right(WritingMode aWritingMode) const
   1.787 +  {
   1.788 +    CHECK_WRITING_MODE(aWritingMode);
   1.789 +    return aWritingMode.IsVertical() ?
   1.790 +      (aWritingMode.IsVerticalLR() ? BEnd() : BStart()) :
   1.791 +      (aWritingMode.IsBidiLTR() ? IEnd() : IStart());
   1.792 +  }
   1.793 +
   1.794 +  nscoord LeftRight(WritingMode aWritingMode) const
   1.795 +  {
   1.796 +    CHECK_WRITING_MODE(aWritingMode);
   1.797 +    return aWritingMode.IsVertical() ? BStartEnd() : IStartEnd();
   1.798 +  }
   1.799 +
   1.800 +  nscoord TopBottom(WritingMode aWritingMode) const
   1.801 +  {
   1.802 +    CHECK_WRITING_MODE(aWritingMode);
   1.803 +    return aWritingMode.IsVertical() ? IStartEnd() : BStartEnd();
   1.804 +  }
   1.805 +
   1.806 +  void SizeTo(WritingMode aWritingMode,
   1.807 +              nscoord aBStart, nscoord aIEnd, nscoord aBEnd, nscoord aIStart)
   1.808 +  {
   1.809 +    CHECK_WRITING_MODE(aWritingMode);
   1.810 +    mMargin.SizeTo(aBStart, aIEnd, aBEnd, aIStart);
   1.811 +  }
   1.812 +
   1.813 +  /**
   1.814 +   * Return an nsMargin containing our physical coordinates
   1.815 +   */
   1.816 +  nsMargin GetPhysicalMargin(WritingMode aWritingMode) const
   1.817 +  {
   1.818 +    CHECK_WRITING_MODE(aWritingMode);
   1.819 +    return aWritingMode.IsVertical() ?
   1.820 +      (aWritingMode.IsVerticalLR() ?
   1.821 +        nsMargin(IStart(), BEnd(), IEnd(), BStart()) :
   1.822 +        nsMargin(IStart(), BStart(), IEnd(), BEnd())) :
   1.823 +      (aWritingMode.IsBidiLTR() ?
   1.824 +        nsMargin(BStart(), IEnd(), BEnd(), IStart()) :
   1.825 +        nsMargin(BStart(), IStart(), BEnd(), IEnd()));
   1.826 +  }
   1.827 +
   1.828 +  /**
   1.829 +   * Return a LogicalMargin representing this margin in a different
   1.830 +   * writing mode
   1.831 +   */
   1.832 +  LogicalMargin ConvertTo(WritingMode aToMode, WritingMode aFromMode) const
   1.833 +  {
   1.834 +    CHECK_WRITING_MODE(aFromMode);
   1.835 +    return aToMode == aFromMode ?
   1.836 +      *this : LogicalMargin(aToMode, GetPhysicalMargin(aFromMode));
   1.837 +  }
   1.838 +
   1.839 +  bool IsEmpty() const
   1.840 +  {
   1.841 +    return (mMargin.left == 0 && mMargin.top == 0 &&
   1.842 +            mMargin.right == 0 && mMargin.bottom == 0);
   1.843 +  }
   1.844 +
   1.845 +  LogicalMargin operator+(const LogicalMargin& aMargin) {
   1.846 +    CHECK_WRITING_MODE(aMargin.GetWritingMode());
   1.847 +    return LogicalMargin(GetWritingMode(),
   1.848 +                         BStart() + aMargin.BStart(),
   1.849 +                         IEnd() + aMargin.IEnd(),
   1.850 +                         BEnd() + aMargin.BEnd(),
   1.851 +                         IStart() + aMargin.IStart());
   1.852 +  }
   1.853 +
   1.854 +  LogicalMargin operator-(const LogicalMargin& aMargin) {
   1.855 +    CHECK_WRITING_MODE(aMargin.GetWritingMode());
   1.856 +    return LogicalMargin(GetWritingMode(),
   1.857 +                         BStart() - aMargin.BStart(),
   1.858 +                         IEnd() - aMargin.IEnd(),
   1.859 +                         BEnd() - aMargin.BEnd(),
   1.860 +                         IStart() - aMargin.IStart());
   1.861 +  }
   1.862 +
   1.863 +private:
   1.864 +  friend class LogicalRect;
   1.865 +
   1.866 +  LogicalMargin() MOZ_DELETE;
   1.867 +
   1.868 +#ifdef DEBUG
   1.869 +  WritingMode GetWritingMode() const { return mWritingMode; }
   1.870 +#else
   1.871 +  WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
   1.872 +#endif
   1.873 +
   1.874 +  nscoord IStart() const // inline-start margin
   1.875 +  {
   1.876 +    return mMargin.left;
   1.877 +  }
   1.878 +  nscoord IEnd() const // inline-end margin
   1.879 +  {
   1.880 +    return mMargin.right;
   1.881 +  }
   1.882 +  nscoord BStart() const // block-start margin
   1.883 +  {
   1.884 +    return mMargin.top;
   1.885 +  }
   1.886 +  nscoord BEnd() const // block-end margin
   1.887 +  {
   1.888 +    return mMargin.bottom;
   1.889 +  }
   1.890 +
   1.891 +  nscoord& IStart() // inline-start margin
   1.892 +  {
   1.893 +    return mMargin.left;
   1.894 +  }
   1.895 +  nscoord& IEnd() // inline-end margin
   1.896 +  {
   1.897 +    return mMargin.right;
   1.898 +  }
   1.899 +  nscoord& BStart() // block-start margin
   1.900 +  {
   1.901 +    return mMargin.top;
   1.902 +  }
   1.903 +  nscoord& BEnd() // block-end margin
   1.904 +  {
   1.905 +    return mMargin.bottom;
   1.906 +  }
   1.907 +
   1.908 +  nscoord IStartEnd() const // inline margins
   1.909 +  {
   1.910 +    return mMargin.LeftRight();
   1.911 +  }
   1.912 +  nscoord BStartEnd() const // block margins
   1.913 +  {
   1.914 +    return mMargin.TopBottom();
   1.915 +  }
   1.916 +
   1.917 +  WritingMode mWritingMode;
   1.918 +  nsMargin    mMargin;
   1.919 +};
   1.920 +
   1.921 +/**
   1.922 + * Flow-relative rectangle
   1.923 + */
   1.924 +class LogicalRect {
   1.925 +public:
   1.926 +  LogicalRect(WritingMode aWritingMode)
   1.927 +    :
   1.928 +#ifdef DEBUG
   1.929 +      mWritingMode(aWritingMode),
   1.930 +#endif
   1.931 +      mRect(0, 0, 0, 0)
   1.932 +  { }
   1.933 +
   1.934 +  LogicalRect(WritingMode aWritingMode,
   1.935 +              nscoord aIStart, nscoord aBStart,
   1.936 +              nscoord aISize, nscoord aBSize)
   1.937 +    :
   1.938 +#ifdef DEBUG
   1.939 +      mWritingMode(aWritingMode),
   1.940 +#endif
   1.941 +      mRect(aIStart, aBStart, aISize, aBSize)
   1.942 +  { }
   1.943 +
   1.944 +  LogicalRect(WritingMode aWritingMode,
   1.945 +              const LogicalPoint& aOrigin,
   1.946 +              const LogicalSize& aSize)
   1.947 +    : 
   1.948 +#ifdef DEBUG
   1.949 +      mWritingMode(aWritingMode),
   1.950 +#endif
   1.951 +      mRect(aOrigin.mPoint, aSize.mSize)
   1.952 +  {
   1.953 +    CHECK_WRITING_MODE(aOrigin.GetWritingMode());
   1.954 +    CHECK_WRITING_MODE(aSize.GetWritingMode());
   1.955 +  }
   1.956 +
   1.957 +  LogicalRect(WritingMode aWritingMode,
   1.958 +              const nsRect& aRect,
   1.959 +              nscoord aContainerWidth)
   1.960 +#ifdef DEBUG
   1.961 +    : mWritingMode(aWritingMode)
   1.962 +#endif
   1.963 +  {
   1.964 +    if (aWritingMode.IsVertical()) {
   1.965 +      if (aWritingMode.IsVerticalLR()) {
   1.966 +        mRect.y = aRect.x;
   1.967 +      } else {
   1.968 +        mRect.y = aContainerWidth - aRect.XMost();
   1.969 +      }
   1.970 +      mRect.height = aRect.width;
   1.971 +      mRect.x = aRect.y;
   1.972 +      mRect.width = aRect.height;
   1.973 +    } else {
   1.974 +      if (aWritingMode.IsBidiLTR()) {
   1.975 +        mRect.x = aRect.x;
   1.976 +      } else {
   1.977 +        mRect.x = aContainerWidth - aRect.XMost();
   1.978 +      }
   1.979 +      mRect.width = aRect.width;
   1.980 +      mRect.y = aRect.y;
   1.981 +      mRect.height = aRect.height;
   1.982 +    }
   1.983 +  }
   1.984 +
   1.985 +  /**
   1.986 +   * Inline- and block-dimension geometry.
   1.987 +   */
   1.988 +  nscoord IStart(WritingMode aWritingMode) const // inline-start edge
   1.989 +  {
   1.990 +    CHECK_WRITING_MODE(aWritingMode);
   1.991 +    return mRect.X();
   1.992 +  }
   1.993 +  nscoord IEnd(WritingMode aWritingMode) const // inline-end edge
   1.994 +  {
   1.995 +    CHECK_WRITING_MODE(aWritingMode);
   1.996 +    return mRect.XMost();
   1.997 +  }
   1.998 +  nscoord ISize(WritingMode aWritingMode) const // inline-size
   1.999 +  {
  1.1000 +    CHECK_WRITING_MODE(aWritingMode);
  1.1001 +    return mRect.Width();
  1.1002 +  }
  1.1003 +
  1.1004 +  nscoord BStart(WritingMode aWritingMode) const // block-start edge
  1.1005 +  {
  1.1006 +    CHECK_WRITING_MODE(aWritingMode);
  1.1007 +    return mRect.Y();
  1.1008 +  }
  1.1009 +  nscoord BEnd(WritingMode aWritingMode) const // block-end edge
  1.1010 +  {
  1.1011 +    CHECK_WRITING_MODE(aWritingMode);
  1.1012 +    return mRect.YMost();
  1.1013 +  }
  1.1014 +  nscoord BSize(WritingMode aWritingMode) const // block-size
  1.1015 +  {
  1.1016 +    CHECK_WRITING_MODE(aWritingMode);
  1.1017 +    return mRect.Height();
  1.1018 +  }
  1.1019 +
  1.1020 +  /**
  1.1021 +   * Writable (reference) accessors are only available for the basic logical
  1.1022 +   * fields (Start and Size), not derivatives like End.
  1.1023 +   */
  1.1024 +  nscoord& IStart(WritingMode aWritingMode) // inline-start edge
  1.1025 +  {
  1.1026 +    CHECK_WRITING_MODE(aWritingMode);
  1.1027 +    return mRect.x;
  1.1028 +  }
  1.1029 +  nscoord& ISize(WritingMode aWritingMode) // inline-size
  1.1030 +  {
  1.1031 +    CHECK_WRITING_MODE(aWritingMode);
  1.1032 +    return mRect.width;
  1.1033 +  }
  1.1034 +  nscoord& BStart(WritingMode aWritingMode) // block-start edge
  1.1035 +  {
  1.1036 +    CHECK_WRITING_MODE(aWritingMode);
  1.1037 +    return mRect.y;
  1.1038 +  }
  1.1039 +  nscoord& BSize(WritingMode aWritingMode) // block-size
  1.1040 +  {
  1.1041 +    CHECK_WRITING_MODE(aWritingMode);
  1.1042 +    return mRect.height;
  1.1043 +  }
  1.1044 +
  1.1045 +  /**
  1.1046 +   * Physical coordinates of the rect.
  1.1047 +   */
  1.1048 +  nscoord X(WritingMode aWritingMode, nscoord aContainerWidth) const
  1.1049 +  {
  1.1050 +    CHECK_WRITING_MODE(aWritingMode);
  1.1051 +    if (aWritingMode.IsVertical()) {
  1.1052 +      return aWritingMode.IsVerticalLR() ?
  1.1053 +             mRect.Y() : aContainerWidth - mRect.YMost();
  1.1054 +    } else {
  1.1055 +      return aWritingMode.IsBidiLTR() ?
  1.1056 +             mRect.X() : aContainerWidth - mRect.XMost();
  1.1057 +    }
  1.1058 +  }
  1.1059 +
  1.1060 +  void SetX(WritingMode aWritingMode, nscoord aX, nscoord aContainerWidth)
  1.1061 +  {
  1.1062 +    CHECK_WRITING_MODE(aWritingMode);
  1.1063 +    if (aWritingMode.IsVertical()) {
  1.1064 +      if (aWritingMode.IsVerticalLR()) {
  1.1065 +        BStart() = aX;
  1.1066 +      } else {
  1.1067 +        BStart() = aContainerWidth - aX - BSize();
  1.1068 +      }
  1.1069 +    } else {
  1.1070 +      if (aWritingMode.IsBidiLTR()) {
  1.1071 +        IStart() = aX;
  1.1072 +      } else {
  1.1073 +        IStart() = aContainerWidth - aX - ISize();
  1.1074 +      }
  1.1075 +    }
  1.1076 +  }
  1.1077 +
  1.1078 +  nscoord Y(WritingMode aWritingMode) const
  1.1079 +  {
  1.1080 +    CHECK_WRITING_MODE(aWritingMode);
  1.1081 +    return aWritingMode.IsVertical() ? mRect.X() : mRect.Y();
  1.1082 +  }
  1.1083 +
  1.1084 +  void SetY(WritingMode aWritingMode, nscoord aY)
  1.1085 +  {
  1.1086 +    CHECK_WRITING_MODE(aWritingMode);
  1.1087 +    if (aWritingMode.IsVertical()) {
  1.1088 +      IStart() = aY;
  1.1089 +    } else {
  1.1090 +      BStart() = aY;
  1.1091 +    }
  1.1092 +  }
  1.1093 +
  1.1094 +  nscoord Width(WritingMode aWritingMode) const
  1.1095 +  {
  1.1096 +    CHECK_WRITING_MODE(aWritingMode);
  1.1097 +    return aWritingMode.IsVertical() ? mRect.Height() : mRect.Width();
  1.1098 +  }
  1.1099 +
  1.1100 +  // When setting the Width of a rect, we keep its physical X-coord fixed
  1.1101 +  // and modify XMax. This means that in the RTL case, we'll be moving
  1.1102 +  // the IStart, so that IEnd remains constant.
  1.1103 +  void SetWidth(WritingMode aWritingMode, nscoord aWidth)
  1.1104 +  {
  1.1105 +    CHECK_WRITING_MODE(aWritingMode);
  1.1106 +    if (aWritingMode.IsVertical()) {
  1.1107 +      if (!aWritingMode.IsVerticalLR()) {
  1.1108 +        BStart() = BStart() + BSize() - aWidth;
  1.1109 +      }
  1.1110 +      BSize() = aWidth;
  1.1111 +    } else {
  1.1112 +      if (!aWritingMode.IsBidiLTR()) {
  1.1113 +        IStart() = IStart() + ISize() - aWidth;
  1.1114 +      }
  1.1115 +      ISize() = aWidth;
  1.1116 +    }
  1.1117 +  }
  1.1118 +
  1.1119 +  nscoord Height(WritingMode aWritingMode) const
  1.1120 +  {
  1.1121 +    CHECK_WRITING_MODE(aWritingMode);
  1.1122 +    return aWritingMode.IsVertical() ? mRect.Width() : mRect.Height();
  1.1123 +  }
  1.1124 +
  1.1125 +  void SetHeight(WritingMode aWritingMode, nscoord aHeight)
  1.1126 +  {
  1.1127 +    CHECK_WRITING_MODE(aWritingMode);
  1.1128 +    if (aWritingMode.IsVertical()) {
  1.1129 +      ISize() = aHeight;
  1.1130 +    } else {
  1.1131 +      BSize() = aHeight;
  1.1132 +    }
  1.1133 +  }
  1.1134 +
  1.1135 +  nscoord XMost(WritingMode aWritingMode, nscoord aContainerWidth) const
  1.1136 +  {
  1.1137 +    CHECK_WRITING_MODE(aWritingMode);
  1.1138 +    if (aWritingMode.IsVertical()) {
  1.1139 +      return aWritingMode.IsVerticalLR() ?
  1.1140 +             mRect.YMost() : aContainerWidth - mRect.Y();
  1.1141 +    } else {
  1.1142 +      return aWritingMode.IsBidiLTR() ?
  1.1143 +             mRect.XMost() : aContainerWidth - mRect.X();
  1.1144 +    }
  1.1145 +  }
  1.1146 +
  1.1147 +  nscoord YMost(WritingMode aWritingMode) const
  1.1148 +  {
  1.1149 +    CHECK_WRITING_MODE(aWritingMode);
  1.1150 +    return aWritingMode.IsVertical() ? mRect.XMost() : mRect.YMost();
  1.1151 +  }
  1.1152 +
  1.1153 +  bool IsEmpty() const
  1.1154 +  {
  1.1155 +    return (mRect.x == 0 && mRect.y == 0 &&
  1.1156 +            mRect.width == 0 && mRect.height == 0);
  1.1157 +  }
  1.1158 +
  1.1159 +  bool IsZeroSize() const
  1.1160 +  {
  1.1161 +    return (mRect.width == 0 && mRect.height == 0);
  1.1162 +  }
  1.1163 +
  1.1164 +/* XXX are these correct?
  1.1165 +  nscoord ILeft(WritingMode aWritingMode) const
  1.1166 +  {
  1.1167 +    CHECK_WRITING_MODE(aWritingMode);
  1.1168 +    return aWritingMode.IsBidiLTR() ? IStart() : IEnd();
  1.1169 +  }
  1.1170 +  nscoord IRight(WritingMode aWritingMode) const
  1.1171 +  {
  1.1172 +    CHECK_WRITING_MODE(aWritingMode);
  1.1173 +    return aWritingMode.IsBidiLTR() ? IEnd() : IStart();
  1.1174 +  }
  1.1175 +*/
  1.1176 +
  1.1177 +  LogicalPoint Origin(WritingMode aWritingMode) const
  1.1178 +  {
  1.1179 +    CHECK_WRITING_MODE(aWritingMode);
  1.1180 +    return LogicalPoint(aWritingMode, IStart(), BStart());
  1.1181 +  }
  1.1182 +  LogicalSize Size(WritingMode aWritingMode) const
  1.1183 +  {
  1.1184 +    CHECK_WRITING_MODE(aWritingMode);
  1.1185 +    return LogicalSize(aWritingMode, ISize(), BSize());
  1.1186 +  }
  1.1187 +
  1.1188 +  LogicalRect operator+(const LogicalPoint& aPoint) const
  1.1189 +  {
  1.1190 +    CHECK_WRITING_MODE(aPoint.GetWritingMode());
  1.1191 +    return LogicalRect(GetWritingMode(),
  1.1192 +                       IStart() + aPoint.I(), BStart() + aPoint.B(),
  1.1193 +                       ISize(), BSize());
  1.1194 +  }
  1.1195 +
  1.1196 +  LogicalRect& operator+=(const LogicalPoint& aPoint)
  1.1197 +  {
  1.1198 +    CHECK_WRITING_MODE(aPoint.GetWritingMode());
  1.1199 +    mRect += aPoint.mPoint;
  1.1200 +    return *this;
  1.1201 +  }
  1.1202 +
  1.1203 +  LogicalRect operator-(const LogicalPoint& aPoint) const
  1.1204 +  {
  1.1205 +    CHECK_WRITING_MODE(aPoint.GetWritingMode());
  1.1206 +    return LogicalRect(GetWritingMode(),
  1.1207 +                       IStart() - aPoint.I(), BStart() - aPoint.B(),
  1.1208 +                       ISize(), BSize());
  1.1209 +  }
  1.1210 +
  1.1211 +  LogicalRect& operator-=(const LogicalPoint& aPoint)
  1.1212 +  {
  1.1213 +    CHECK_WRITING_MODE(aPoint.GetWritingMode());
  1.1214 +    mRect -= aPoint.mPoint;
  1.1215 +    return *this;
  1.1216 +  }
  1.1217 +
  1.1218 +  void MoveBy(WritingMode aWritingMode, const LogicalPoint& aDelta)
  1.1219 +  {
  1.1220 +    CHECK_WRITING_MODE(aWritingMode);
  1.1221 +    CHECK_WRITING_MODE(aDelta.GetWritingMode());
  1.1222 +    IStart() += aDelta.I();
  1.1223 +    BStart() += aDelta.B();
  1.1224 +  }
  1.1225 +
  1.1226 +  void Inflate(nscoord aD) { mRect.Inflate(aD); }
  1.1227 +  void Inflate(nscoord aDI, nscoord aDB) { mRect.Inflate(aDI, aDB); }
  1.1228 +  void Inflate(WritingMode aWritingMode, const LogicalMargin& aMargin)
  1.1229 +  {
  1.1230 +    CHECK_WRITING_MODE(aWritingMode);
  1.1231 +    CHECK_WRITING_MODE(aMargin.GetWritingMode());
  1.1232 +    mRect.Inflate(aMargin.mMargin);
  1.1233 +  }
  1.1234 +
  1.1235 +  void Deflate(nscoord aD) { mRect.Deflate(aD); }
  1.1236 +  void Deflate(nscoord aDI, nscoord aDB) { mRect.Deflate(aDI, aDB); }
  1.1237 +  void Deflate(WritingMode aWritingMode, const LogicalMargin& aMargin)
  1.1238 +  {
  1.1239 +    CHECK_WRITING_MODE(aWritingMode);
  1.1240 +    CHECK_WRITING_MODE(aMargin.GetWritingMode());
  1.1241 +    mRect.Deflate(aMargin.mMargin);
  1.1242 +  }
  1.1243 +
  1.1244 +  /**
  1.1245 +   * Return an nsRect containing our physical coordinates within the given
  1.1246 +   * container width
  1.1247 +   */
  1.1248 +  nsRect GetPhysicalRect(WritingMode aWritingMode,
  1.1249 +                         nscoord aContainerWidth) const
  1.1250 +  {
  1.1251 +    CHECK_WRITING_MODE(aWritingMode);
  1.1252 +    if (aWritingMode.IsVertical()) {
  1.1253 +      return nsRect(aWritingMode.IsVerticalLR() ?
  1.1254 +                      BStart() : aContainerWidth - BEnd(),
  1.1255 +                    IStart(), BSize(), ISize());
  1.1256 +    } else {
  1.1257 +      return nsRect(aWritingMode.IsBidiLTR() ?
  1.1258 +                      IStart() : aContainerWidth - IEnd(),
  1.1259 +                    BStart(), ISize(), BSize());
  1.1260 +    }
  1.1261 +  }
  1.1262 +
  1.1263 +#if 0 // XXX this would require aContainerWidth as well
  1.1264 +  /**
  1.1265 +   * Return a LogicalRect representing this rect in a different writing mode
  1.1266 +   */
  1.1267 +  LogicalRect ConvertTo(WritingMode aToMode, WritingMode aFromMode) const
  1.1268 +  {
  1.1269 +    CHECK_WRITING_MODE(aFromMode);
  1.1270 +    return aToMode == aFromMode ?
  1.1271 +      *this : LogicalRect(aToMode, GetPhysicalRect(aFromMode));
  1.1272 +  }
  1.1273 +#endif
  1.1274 +
  1.1275 +private:
  1.1276 +  LogicalRect() MOZ_DELETE;
  1.1277 +
  1.1278 +#ifdef DEBUG
  1.1279 +  WritingMode GetWritingMode() const { return mWritingMode; }
  1.1280 +#else
  1.1281 +  WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
  1.1282 +#endif
  1.1283 +
  1.1284 +  nscoord IStart() const // inline-start edge
  1.1285 +  {
  1.1286 +    return mRect.X();
  1.1287 +  }
  1.1288 +  nscoord IEnd() const // inline-end edge
  1.1289 +  {
  1.1290 +    return mRect.XMost();
  1.1291 +  }
  1.1292 +  nscoord ISize() const // inline-size
  1.1293 +  {
  1.1294 +    return mRect.Width();
  1.1295 +  }
  1.1296 +
  1.1297 +  nscoord BStart() const // block-start edge
  1.1298 +  {
  1.1299 +    return mRect.Y();
  1.1300 +  }
  1.1301 +  nscoord BEnd() const // block-end edge
  1.1302 +  {
  1.1303 +    return mRect.YMost();
  1.1304 +  }
  1.1305 +  nscoord BSize() const // block-size
  1.1306 +  {
  1.1307 +    return mRect.Height();
  1.1308 +  }
  1.1309 +
  1.1310 +  nscoord& IStart() // inline-start edge
  1.1311 +  {
  1.1312 +    return mRect.x;
  1.1313 +  }
  1.1314 +  nscoord& ISize() // inline-size
  1.1315 +  {
  1.1316 +    return mRect.width;
  1.1317 +  }
  1.1318 +  nscoord& BStart() // block-start edge
  1.1319 +  {
  1.1320 +    return mRect.y;
  1.1321 +  }
  1.1322 +  nscoord& BSize() // block-size
  1.1323 +  {
  1.1324 +    return mRect.height;
  1.1325 +  }
  1.1326 +
  1.1327 +  WritingMode mWritingMode;
  1.1328 +  nsRect      mRect;
  1.1329 +};
  1.1330 +
  1.1331 +} // namespace mozilla
  1.1332 +
  1.1333 +#endif // WritingModes_h_

mercurial