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_