Bumping manifests a=b2g-bump
[gecko.git] / layout / generic / WritingModes.h
blobc8db9777ee07255aeb2ec6a9d181a4ca89baf37d
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef WritingModes_h_
7 #define WritingModes_h_
9 #include "nsRect.h"
10 #include "nsStyleStruct.h"
12 // If WRITING_MODE_VERTICAL_ENABLED is defined, we will attempt to support
13 // the vertical writing-mode values; if it is not defined, then
14 // WritingMode.IsVertical() will be hard-coded to return false, allowing
15 // many conditional branches to be optimized away while we're in the process
16 // of transitioning layout to use writing-mode and logical directions, but
17 // not yet ready to ship vertical support.
19 /* #define WRITING_MODE_VERTICAL_ENABLED 1 */
21 // It is the caller's responsibility to operate on logical-coordinate objects
22 // with matched writing modes. Failure to do so will be a runtime bug; the
23 // compiler can't catch it, but in debug mode, we'll throw an assertion.
24 // NOTE that in non-debug builds, a writing mode mismatch error will NOT be
25 // detected, yet the results will be nonsense (and may lead to further layout
26 // failures). Therefore, it is important to test (and fuzz-test) writing-mode
27 // support using debug builds.
29 // Methods in logical-coordinate classes that take another logical-coordinate
30 // object as a parameter should call CHECK_WRITING_MODE on it to verify that
31 // the writing modes match.
32 // (In some cases, there are internal (private) methods that don't do this;
33 // such methods should only be used by other methods that have already checked
34 // the writing modes.)
36 #define CHECK_WRITING_MODE(param) \
37 NS_ASSERTION(param == mWritingMode, "writing-mode mismatch")
39 namespace mozilla {
40 // Logical side constants for use in various places.
41 enum LogicalSide { eLogicalSideBStart, eLogicalSideBEnd,
42 eLogicalSideIStart, eLogicalSideIEnd };
44 enum LogicalSideBits {
45 eLogicalSideBitsNone = 0,
46 eLogicalSideBitsBStart = 1 << eLogicalSideBStart,
47 eLogicalSideBitsBEnd = 1 << eLogicalSideBEnd,
48 eLogicalSideBitsIEnd = 1 << eLogicalSideIEnd,
49 eLogicalSideBitsIStart = 1 << eLogicalSideIStart,
50 eLogicalSideBitsBBoth = eLogicalSideBitsBStart | eLogicalSideBitsBEnd,
51 eLogicalSideBitsIBoth = eLogicalSideBitsIStart | eLogicalSideBitsIEnd,
52 eLogicalSideBitsAll = eLogicalSideBitsBBoth | eLogicalSideBitsIBoth
55 /**
56 * LogicalSides represents a set of logical sides.
58 struct LogicalSides MOZ_FINAL {
59 LogicalSides() : mBits(0) {}
60 explicit LogicalSides(LogicalSideBits aSideBits)
62 MOZ_ASSERT((aSideBits & ~eLogicalSideBitsAll) == 0, "illegal side bits");
63 mBits = aSideBits;
65 bool IsEmpty() const { return mBits == 0; }
66 bool BStart() const { return mBits & eLogicalSideBitsBStart; }
67 bool BEnd() const { return mBits & eLogicalSideBitsBEnd; }
68 bool IStart() const { return mBits & eLogicalSideBitsIStart; }
69 bool IEnd() const { return mBits & eLogicalSideBitsIEnd; }
70 bool Contains(LogicalSideBits aSideBits) const
72 MOZ_ASSERT((aSideBits & ~eLogicalSideBitsAll) == 0, "illegal side bits");
73 return (mBits & aSideBits) == aSideBits;
75 LogicalSides operator|(LogicalSides aOther) const
77 return LogicalSides(LogicalSideBits(mBits | aOther.mBits));
79 LogicalSides operator|(LogicalSideBits aSideBits) const
81 return *this | LogicalSides(aSideBits);
83 LogicalSides& operator|=(LogicalSides aOther)
85 mBits |= aOther.mBits;
86 return *this;
88 LogicalSides& operator|=(LogicalSideBits aSideBits)
90 return *this |= LogicalSides(aSideBits);
92 bool operator==(LogicalSides aOther) const
94 return mBits == aOther.mBits;
96 bool operator!=(LogicalSides aOther) const
98 return !(*this == aOther);
101 private:
102 uint8_t mBits;
106 * mozilla::WritingMode is an immutable class representing a
107 * writing mode.
109 * It efficiently stores the writing mode and can rapidly compute
110 * interesting things about it for use in layout.
112 * Writing modes are computed from the CSS 'direction',
113 * 'writing-mode', and 'text-orientation' properties.
114 * See CSS3 Writing Modes for more information
115 * http://www.w3.org/TR/css3-writing-modes/
117 class WritingMode {
118 public:
120 * Absolute inline flow direction
122 enum InlineDir {
123 eInlineLTR = 0x00, // text flows horizontally left to right
124 eInlineRTL = 0x02, // text flows horizontally right to left
125 eInlineTTB = 0x01, // text flows vertically top to bottom
126 eInlineBTT = 0x03, // text flows vertically bottom to top
130 * Absolute block flow direction
132 enum BlockDir {
133 eBlockTB = 0x00, // horizontal lines stack top to bottom
134 eBlockRL = 0x01, // vertical lines stack right to left
135 eBlockLR = 0x05, // vertical lines stack left to right
139 * Line-relative (bidi-relative) inline flow direction
141 enum BidiDir {
142 eBidiLTR = 0x00, // inline flow matches bidi LTR text
143 eBidiRTL = 0x10, // inline flow matches bidi RTL text
147 * Unknown writing mode (should never actually be stored or used anywhere).
149 enum {
150 eUnknownWritingMode = 0xff
154 * Return the absolute inline flow direction as an InlineDir
156 InlineDir GetInlineDir() const { return InlineDir(mWritingMode & eInlineMask); }
159 * Return the absolute block flow direction as a BlockDir
161 BlockDir GetBlockDir() const { return BlockDir(mWritingMode & eBlockMask); }
164 * Return the line-relative inline flow direction as a BidiDir
166 BidiDir GetBidiDir() const { return BidiDir(mWritingMode & eBidiMask); }
169 * Return true if LTR. (Convenience method)
171 bool IsBidiLTR() const { return eBidiLTR == (mWritingMode & eBidiMask); }
174 * True if vertical-mode block direction is LR (convenience method).
176 bool IsVerticalLR() const { return eBlockLR == (mWritingMode & eBlockMask); }
179 * True if vertical writing mode, i.e. when
180 * writing-mode: vertical-lr | vertical-rl.
182 #ifdef WRITING_MODE_VERTICAL_ENABLED
183 bool IsVertical() const { return !!(mWritingMode & eOrientationMask); }
184 #else
185 bool IsVertical() const { return false; }
186 #endif
189 * True if line-over/line-under are inverted from block-start/block-end.
190 * This is true when
191 * - writing-mode is vertical-rl && text-orientation is sideways-left
192 * - writing-mode is vertical-lr && text-orientation is not sideways-left
194 #ifdef WRITING_MODE_VERTICAL_ENABLED
195 bool IsLineInverted() const { return !!(mWritingMode & eLineOrientMask); }
196 #else
197 bool IsLineInverted() const { return false; }
198 #endif
201 * Block-axis flow-relative to line-relative factor.
202 * May be used as a multiplication factor for block-axis coordinates
203 * to convert between flow- and line-relative coordinate systems (e.g.
204 * positioning an over- or under-line decoration).
206 int FlowRelativeToLineRelativeFactor() const
208 return IsLineInverted() ? -1 : 1;
212 * Default constructor gives us a horizontal, LTR writing mode.
213 * XXX We will probably eliminate this and require explicit initialization
214 * in all cases once transition is complete.
216 WritingMode()
217 : mWritingMode(0)
221 * Construct writing mode based on a style context
223 explicit WritingMode(const nsStyleVisibility* aStyleVisibility)
225 NS_ASSERTION(aStyleVisibility, "we need an nsStyleVisibility here");
227 #ifdef WRITING_MODE_VERTICAL_ENABLED
228 switch (aStyleVisibility->mWritingMode) {
229 case NS_STYLE_WRITING_MODE_HORIZONTAL_TB:
230 mWritingMode = 0;
231 break;
233 case NS_STYLE_WRITING_MODE_VERTICAL_LR:
234 mWritingMode = eBlockFlowMask |
235 eLineOrientMask | //XXX needs update when text-orientation added
236 eOrientationMask;
237 break;
239 case NS_STYLE_WRITING_MODE_VERTICAL_RL:
240 mWritingMode = eOrientationMask;
241 break;
243 default:
244 NS_NOTREACHED("unknown writing mode!");
245 mWritingMode = 0;
246 break;
248 #else
249 mWritingMode = 0;
250 #endif
252 if (NS_STYLE_DIRECTION_RTL == aStyleVisibility->mDirection) {
253 mWritingMode |= eInlineFlowMask | //XXX needs update when text-orientation added
254 eBidiMask;
258 // For unicode-bidi: plaintext, reset the direction of the writing mode from
259 // the bidi paragraph level of the content
261 //XXX change uint8_t to UBiDiLevel after bug 924851
262 void SetDirectionFromBidiLevel(uint8_t level)
264 if (level & 1) {
265 // odd level, set RTL
266 mWritingMode |= eBidiMask;
267 } else {
268 // even level, set LTR
269 mWritingMode &= ~eBidiMask;
274 * Compare two WritingModes for equality.
276 bool operator==(const WritingMode& aOther) const
278 return mWritingMode == aOther.mWritingMode;
281 bool operator!=(const WritingMode& aOther) const
283 return mWritingMode != aOther.mWritingMode;
286 private:
287 friend class LogicalPoint;
288 friend class LogicalSize;
289 friend class LogicalMargin;
290 friend class LogicalRect;
293 * Return a WritingMode representing an unknown value.
295 static inline WritingMode Unknown()
297 return WritingMode(eUnknownWritingMode);
301 * Constructing a WritingMode with an arbitrary value is a private operation
302 * currently only used by the Unknown() static method.
304 explicit WritingMode(uint8_t aValue)
305 : mWritingMode(aValue)
308 uint8_t mWritingMode;
310 enum Masks {
311 // Masks for our bits; true chosen as opposite of commonest case
312 eOrientationMask = 0x01, // true means vertical text
313 eInlineFlowMask = 0x02, // true means absolute RTL/BTT (against physical coords)
314 eBlockFlowMask = 0x04, // true means vertical-LR (or horizontal-BT if added)
315 eLineOrientMask = 0x08, // true means over != block-start
316 eBidiMask = 0x10, // true means line-relative RTL (bidi RTL)
317 // Note: We have one excess bit of info; WritingMode can pack into 4 bits.
318 // But since we have space, we're caching interesting things for fast access.
320 // Masks for output enums
321 eInlineMask = 0x03,
322 eBlockMask = 0x05
328 * Logical-coordinate classes:
330 * There are three sets of coordinate space:
331 * - physical (top, left, bottom, right)
332 * relative to graphics coord system
333 * - flow-relative (block-start, inline-start, block-end, inline-end)
334 * relative to block/inline flow directions
335 * - line-relative (line-over, line-left, line-under, line-right)
336 * relative to glyph orientation / inline bidi directions
337 * See CSS3 Writing Modes for more information
338 * http://www.w3.org/TR/css3-writing-modes/#abstract-box
340 * For shorthand, B represents the block-axis
341 * I represents the inline-axis
343 * The flow-relative geometric classes store coords in flow-relative space.
344 * They use a private ns{Point,Size,Rect,Margin} member to store the actual
345 * coordinate values, but reinterpret them as logical instead of physical.
346 * This allows us to easily perform calculations in logical space (provided
347 * writing modes of the operands match), by simply mapping to nsPoint (etc)
348 * methods.
350 * Physical-coordinate accessors/setters are responsible to translate these
351 * internal logical values as necessary.
353 * In DEBUG builds, the logical types store their WritingMode and check
354 * that the same WritingMode is passed whenever callers ask them to do a
355 * writing-mode-dependent operation. Non-DEBUG builds do NOT check this,
356 * to avoid the overhead of storing WritingMode fields.
358 * Open question: do we need a different set optimized for line-relative
359 * math, for use in nsLineLayout and the like? Or is multiplying values
360 * by FlowRelativeToLineRelativeFactor() enough?
364 * Flow-relative point
366 class LogicalPoint {
367 public:
368 explicit LogicalPoint(WritingMode aWritingMode)
370 #ifdef DEBUG
371 mWritingMode(aWritingMode),
372 #endif
373 mPoint(0, 0)
376 // Construct from a writing mode and individual coordinates (which MUST be
377 // values in that writing mode, NOT physical coordinates!)
378 LogicalPoint(WritingMode aWritingMode, nscoord aI, nscoord aB)
380 #ifdef DEBUG
381 mWritingMode(aWritingMode),
382 #endif
383 mPoint(aI, aB)
386 // Construct from a writing mode and a physical point, within a given
387 // containing rectangle's width (defining the conversion between LTR
388 // and RTL coordinates).
389 LogicalPoint(WritingMode aWritingMode,
390 const nsPoint& aPoint,
391 nscoord aContainerWidth)
392 #ifdef DEBUG
393 : mWritingMode(aWritingMode)
394 #endif
396 if (aWritingMode.IsVertical()) {
397 I() = aPoint.y;
398 B() = aWritingMode.IsVerticalLR() ? aPoint.x : aContainerWidth - aPoint.x;
399 } else {
400 I() = aWritingMode.IsBidiLTR() ? aPoint.x : aContainerWidth - aPoint.x;
401 B() = aPoint.y;
406 * Read-only (const) access to the coordinates, in both logical
407 * and physical terms.
409 nscoord I(WritingMode aWritingMode) const // inline-axis
411 CHECK_WRITING_MODE(aWritingMode);
412 return mPoint.x;
414 nscoord B(WritingMode aWritingMode) const // block-axis
416 CHECK_WRITING_MODE(aWritingMode);
417 return mPoint.y;
420 nscoord X(WritingMode aWritingMode, nscoord aContainerWidth) const
422 CHECK_WRITING_MODE(aWritingMode);
423 if (aWritingMode.IsVertical()) {
424 return aWritingMode.IsVerticalLR() ? B() : aContainerWidth - B();
425 } else {
426 return aWritingMode.IsBidiLTR() ? I() : aContainerWidth - I();
429 nscoord Y(WritingMode aWritingMode) const
431 CHECK_WRITING_MODE(aWritingMode);
432 return aWritingMode.IsVertical() ? I() : B();
436 * These non-const accessors return a reference (lvalue) that can be
437 * assigned to by callers.
439 nscoord& I(WritingMode aWritingMode) // inline-axis
441 CHECK_WRITING_MODE(aWritingMode);
442 return mPoint.x;
444 nscoord& B(WritingMode aWritingMode) // block-axis
446 CHECK_WRITING_MODE(aWritingMode);
447 return mPoint.y;
451 * Setters for the physical coordinates.
453 void SetX(WritingMode aWritingMode, nscoord aX, nscoord aContainerWidth)
455 CHECK_WRITING_MODE(aWritingMode);
456 if (aWritingMode.IsVertical()) {
457 B() = aWritingMode.IsVerticalLR() ? aX : aContainerWidth - aX;
458 } else {
459 I() = aWritingMode.IsBidiLTR() ? aX : aContainerWidth - aX;
462 void SetY(WritingMode aWritingMode, nscoord aY)
464 CHECK_WRITING_MODE(aWritingMode);
465 if (aWritingMode.IsVertical()) {
466 B() = aY;
467 } else {
468 I() = aY;
473 * Return a physical point corresponding to our logical coordinates,
474 * converted according to our writing mode.
476 nsPoint GetPhysicalPoint(WritingMode aWritingMode,
477 nscoord aContainerWidth) const
479 CHECK_WRITING_MODE(aWritingMode);
480 if (aWritingMode.IsVertical()) {
481 return nsPoint(aWritingMode.IsVerticalLR() ? B() : aContainerWidth - B(),
482 I());
483 } else {
484 return nsPoint(aWritingMode.IsBidiLTR() ? I() : aContainerWidth - I(),
485 B());
490 * Return the equivalent point in a different writing mode.
492 LogicalPoint ConvertTo(WritingMode aToMode, WritingMode aFromMode,
493 nscoord aContainerWidth) const
495 CHECK_WRITING_MODE(aFromMode);
496 return aToMode == aFromMode ?
497 *this : LogicalPoint(aToMode,
498 GetPhysicalPoint(aFromMode, aContainerWidth),
499 aContainerWidth);
502 LogicalPoint operator+(const LogicalPoint& aOther) const
504 CHECK_WRITING_MODE(aOther.GetWritingMode());
505 // In non-debug builds, LogicalPoint does not store the WritingMode,
506 // so the first parameter here (which will always be eUnknownWritingMode)
507 // is ignored.
508 return LogicalPoint(GetWritingMode(),
509 mPoint.x + aOther.mPoint.x,
510 mPoint.y + aOther.mPoint.y);
513 private:
514 friend class LogicalRect;
517 * NOTE that in non-DEBUG builds, GetWritingMode() always returns
518 * eUnknownWritingMode, as the current mode is not stored in the logical-
519 * geometry classes. Therefore, this method is private; it is used ONLY
520 * by the DEBUG-mode checking macros in this class and its friends;
521 * other code is not allowed to ask a logical point for its writing mode,
522 * as this info will simply not be available in non-DEBUG builds.
524 * Also, in non-DEBUG builds, CHECK_WRITING_MODE does nothing, and the
525 * WritingMode parameter to logical methods will generally be optimized
526 * away altogether.
528 #ifdef DEBUG
529 WritingMode GetWritingMode() const { return mWritingMode; }
530 #else
531 WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
532 #endif
534 // We don't allow construction of a LogicalPoint with no writing mode.
535 LogicalPoint() MOZ_DELETE;
537 // Accessors that don't take or check a WritingMode value.
538 // These are for internal use only; they are called by methods that have
539 // themselves already checked the WritingMode passed by the caller.
540 nscoord I() const // inline-axis
542 return mPoint.x;
544 nscoord B() const // block-axis
546 return mPoint.y;
549 nscoord& I() // inline-axis
551 return mPoint.x;
553 nscoord& B() // block-axis
555 return mPoint.y;
558 WritingMode mWritingMode;
560 // We use an nsPoint to hold the coordinates, but reinterpret its .x and .y
561 // fields as the inline and block directions. Hence, this is not exposed
562 // directly, but only through accessors that will map them according to the
563 // writing mode.
564 nsPoint mPoint;
568 * Flow-relative size
570 class LogicalSize {
571 public:
572 explicit LogicalSize(WritingMode aWritingMode)
574 #ifdef DEBUG
575 mWritingMode(aWritingMode),
576 #endif
577 mSize(0, 0)
580 LogicalSize(WritingMode aWritingMode, nscoord aISize, nscoord aBSize)
582 #ifdef DEBUG
583 mWritingMode(aWritingMode),
584 #endif
585 mSize(aISize, aBSize)
588 LogicalSize(WritingMode aWritingMode, const nsSize& aPhysicalSize)
589 #ifdef DEBUG
590 : mWritingMode(aWritingMode)
591 #endif
593 if (aWritingMode.IsVertical()) {
594 ISize() = aPhysicalSize.height;
595 BSize() = aPhysicalSize.width;
596 } else {
597 ISize() = aPhysicalSize.width;
598 BSize() = aPhysicalSize.height;
602 void SizeTo(WritingMode aWritingMode, nscoord aISize, nscoord aBSize)
604 CHECK_WRITING_MODE(aWritingMode);
605 mSize.SizeTo(aISize, aBSize);
609 * Dimensions in logical and physical terms
611 nscoord ISize(WritingMode aWritingMode) const // inline-size
613 CHECK_WRITING_MODE(aWritingMode);
614 return mSize.width;
616 nscoord BSize(WritingMode aWritingMode) const // block-size
618 CHECK_WRITING_MODE(aWritingMode);
619 return mSize.height;
622 nscoord Width(WritingMode aWritingMode) const
624 CHECK_WRITING_MODE(aWritingMode);
625 return aWritingMode.IsVertical() ? BSize() : ISize();
627 nscoord Height(WritingMode aWritingMode) const
629 CHECK_WRITING_MODE(aWritingMode);
630 return aWritingMode.IsVertical() ? ISize() : BSize();
634 * Writable references to the logical and physical dimensions
636 nscoord& ISize(WritingMode aWritingMode) // inline-size
638 CHECK_WRITING_MODE(aWritingMode);
639 return mSize.width;
641 nscoord& BSize(WritingMode aWritingMode) // block-size
643 CHECK_WRITING_MODE(aWritingMode);
644 return mSize.height;
647 nscoord& Width(WritingMode aWritingMode)
649 CHECK_WRITING_MODE(aWritingMode);
650 return aWritingMode.IsVertical() ? BSize() : ISize();
652 nscoord& Height(WritingMode aWritingMode)
654 CHECK_WRITING_MODE(aWritingMode);
655 return aWritingMode.IsVertical() ? ISize() : BSize();
659 * Return an nsSize containing our physical dimensions
661 nsSize GetPhysicalSize(WritingMode aWritingMode) const
663 CHECK_WRITING_MODE(aWritingMode);
664 return aWritingMode.IsVertical() ?
665 nsSize(BSize(), ISize()) : nsSize(ISize(), BSize());
669 * Return a LogicalSize representing this size in a different writing mode
671 LogicalSize ConvertTo(WritingMode aToMode, WritingMode aFromMode) const
673 CHECK_WRITING_MODE(aFromMode);
674 return aToMode == aFromMode ?
675 *this : LogicalSize(aToMode, GetPhysicalSize(aFromMode));
678 bool operator==(const LogicalSize& aOther) const
680 return mWritingMode == aOther.mWritingMode && mSize == aOther.mSize;
683 bool operator!=(const LogicalSize& aOther) const
685 return mWritingMode != aOther.mWritingMode || mSize != aOther.mSize;
688 LogicalSize operator+(const LogicalSize& aOther) const
690 CHECK_WRITING_MODE(aOther.GetWritingMode());
691 return LogicalSize(mWritingMode, ISize() + aOther.ISize(),
692 BSize() + aOther.BSize());
694 LogicalSize& operator+=(const LogicalSize& aOther)
696 CHECK_WRITING_MODE(aOther.GetWritingMode());
697 ISize() += aOther.ISize();
698 BSize() += aOther.BSize();
699 return *this;
702 LogicalSize operator-(const LogicalSize& aOther) const
704 CHECK_WRITING_MODE(aOther.GetWritingMode());
705 return LogicalSize(mWritingMode, ISize() - aOther.ISize(),
706 BSize() - aOther.BSize());
708 LogicalSize& operator-=(const LogicalSize& aOther)
710 CHECK_WRITING_MODE(aOther.GetWritingMode());
711 ISize() -= aOther.ISize();
712 BSize() -= aOther.BSize();
713 return *this;
716 private:
717 friend class LogicalRect;
719 LogicalSize() MOZ_DELETE;
721 #ifdef DEBUG
722 WritingMode GetWritingMode() const { return mWritingMode; }
723 #else
724 WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
725 #endif
727 nscoord ISize() const // inline-size
729 return mSize.width;
731 nscoord BSize() const // block-size
733 return mSize.height;
736 nscoord& ISize() // inline-size
738 return mSize.width;
740 nscoord& BSize() // block-size
742 return mSize.height;
745 WritingMode mWritingMode;
746 nsSize mSize;
750 * Flow-relative margin
752 class LogicalMargin {
753 public:
754 explicit LogicalMargin(WritingMode aWritingMode)
756 #ifdef DEBUG
757 mWritingMode(aWritingMode),
758 #endif
759 mMargin(0, 0, 0, 0)
762 LogicalMargin(WritingMode aWritingMode,
763 nscoord aBStart, nscoord aIEnd,
764 nscoord aBEnd, nscoord aIStart)
766 #ifdef DEBUG
767 mWritingMode(aWritingMode),
768 #endif
769 mMargin(aBStart, aIEnd, aBEnd, aIStart)
772 LogicalMargin(WritingMode aWritingMode, const nsMargin& aPhysicalMargin)
773 #ifdef DEBUG
774 : mWritingMode(aWritingMode)
775 #endif
777 if (aWritingMode.IsVertical()) {
778 if (aWritingMode.IsVerticalLR()) {
779 mMargin.top = aPhysicalMargin.left;
780 mMargin.bottom = aPhysicalMargin.right;
781 } else {
782 mMargin.top = aPhysicalMargin.right;
783 mMargin.bottom = aPhysicalMargin.left;
785 if (aWritingMode.IsBidiLTR()) {
786 mMargin.left = aPhysicalMargin.top;
787 mMargin.right = aPhysicalMargin.bottom;
788 } else {
789 mMargin.left = aPhysicalMargin.bottom;
790 mMargin.right = aPhysicalMargin.top;
792 } else {
793 mMargin.top = aPhysicalMargin.top;
794 mMargin.bottom = aPhysicalMargin.bottom;
795 if (aWritingMode.IsBidiLTR()) {
796 mMargin.left = aPhysicalMargin.left;
797 mMargin.right = aPhysicalMargin.right;
798 } else {
799 mMargin.left = aPhysicalMargin.right;
800 mMargin.right = aPhysicalMargin.left;
805 nscoord IStart(WritingMode aWritingMode) const // inline-start margin
807 CHECK_WRITING_MODE(aWritingMode);
808 return mMargin.left;
810 nscoord IEnd(WritingMode aWritingMode) const // inline-end margin
812 CHECK_WRITING_MODE(aWritingMode);
813 return mMargin.right;
815 nscoord BStart(WritingMode aWritingMode) const // block-start margin
817 CHECK_WRITING_MODE(aWritingMode);
818 return mMargin.top;
820 nscoord BEnd(WritingMode aWritingMode) const // block-end margin
822 CHECK_WRITING_MODE(aWritingMode);
823 return mMargin.bottom;
826 nscoord& IStart(WritingMode aWritingMode) // inline-start margin
828 CHECK_WRITING_MODE(aWritingMode);
829 return mMargin.left;
831 nscoord& IEnd(WritingMode aWritingMode) // inline-end margin
833 CHECK_WRITING_MODE(aWritingMode);
834 return mMargin.right;
836 nscoord& BStart(WritingMode aWritingMode) // block-start margin
838 CHECK_WRITING_MODE(aWritingMode);
839 return mMargin.top;
841 nscoord& BEnd(WritingMode aWritingMode) // block-end margin
843 CHECK_WRITING_MODE(aWritingMode);
844 return mMargin.bottom;
847 nscoord IStartEnd(WritingMode aWritingMode) const // inline margins
849 CHECK_WRITING_MODE(aWritingMode);
850 return mMargin.LeftRight();
852 nscoord BStartEnd(WritingMode aWritingMode) const // block margins
854 CHECK_WRITING_MODE(aWritingMode);
855 return mMargin.TopBottom();
859 * Return a LogicalSize representing the total size of the inline-
860 * and block-dimension margins.
862 LogicalSize Size(WritingMode aWritingMode) const
864 CHECK_WRITING_MODE(aWritingMode);
865 return LogicalSize(aWritingMode, IStartEnd(), BStartEnd());
869 * Accessors for physical margins, using our writing mode to convert from
870 * logical values.
872 nscoord Top(WritingMode aWritingMode) const
874 CHECK_WRITING_MODE(aWritingMode);
875 return aWritingMode.IsVertical() ?
876 (aWritingMode.IsBidiLTR() ? IStart() : IEnd()) : BStart();
879 nscoord Bottom(WritingMode aWritingMode) const
881 CHECK_WRITING_MODE(aWritingMode);
882 return aWritingMode.IsVertical() ?
883 (aWritingMode.IsBidiLTR() ? IEnd() : IStart()) : BEnd();
886 nscoord Left(WritingMode aWritingMode) const
888 CHECK_WRITING_MODE(aWritingMode);
889 return aWritingMode.IsVertical() ?
890 (aWritingMode.IsVerticalLR() ? BStart() : BEnd()) :
891 (aWritingMode.IsBidiLTR() ? IStart() : IEnd());
894 nscoord Right(WritingMode aWritingMode) const
896 CHECK_WRITING_MODE(aWritingMode);
897 return aWritingMode.IsVertical() ?
898 (aWritingMode.IsVerticalLR() ? BEnd() : BStart()) :
899 (aWritingMode.IsBidiLTR() ? IEnd() : IStart());
902 nscoord LeftRight(WritingMode aWritingMode) const
904 CHECK_WRITING_MODE(aWritingMode);
905 return aWritingMode.IsVertical() ? BStartEnd() : IStartEnd();
908 nscoord TopBottom(WritingMode aWritingMode) const
910 CHECK_WRITING_MODE(aWritingMode);
911 return aWritingMode.IsVertical() ? IStartEnd() : BStartEnd();
914 void SizeTo(WritingMode aWritingMode,
915 nscoord aBStart, nscoord aIEnd, nscoord aBEnd, nscoord aIStart)
917 CHECK_WRITING_MODE(aWritingMode);
918 mMargin.SizeTo(aBStart, aIEnd, aBEnd, aIStart);
922 * Return an nsMargin containing our physical coordinates
924 nsMargin GetPhysicalMargin(WritingMode aWritingMode) const
926 CHECK_WRITING_MODE(aWritingMode);
927 return aWritingMode.IsVertical() ?
928 (aWritingMode.IsVerticalLR() ?
929 nsMargin(IStart(), BEnd(), IEnd(), BStart()) :
930 nsMargin(IStart(), BStart(), IEnd(), BEnd())) :
931 (aWritingMode.IsBidiLTR() ?
932 nsMargin(BStart(), IEnd(), BEnd(), IStart()) :
933 nsMargin(BStart(), IStart(), BEnd(), IEnd()));
937 * Return a LogicalMargin representing this margin in a different
938 * writing mode
940 LogicalMargin ConvertTo(WritingMode aToMode, WritingMode aFromMode) const
942 CHECK_WRITING_MODE(aFromMode);
943 return aToMode == aFromMode ?
944 *this : LogicalMargin(aToMode, GetPhysicalMargin(aFromMode));
947 void ApplySkipSides(LogicalSides aSkipSides)
949 if (aSkipSides.BStart()) {
950 BStart() = 0;
952 if (aSkipSides.BEnd()) {
953 BEnd() = 0;
955 if (aSkipSides.IStart()) {
956 IStart() = 0;
958 if (aSkipSides.IEnd()) {
959 IEnd() = 0;
963 bool IsEmpty() const
965 return (mMargin.left == 0 && mMargin.top == 0 &&
966 mMargin.right == 0 && mMargin.bottom == 0);
969 LogicalMargin operator+(const LogicalMargin& aMargin) {
970 CHECK_WRITING_MODE(aMargin.GetWritingMode());
971 return LogicalMargin(GetWritingMode(),
972 BStart() + aMargin.BStart(),
973 IEnd() + aMargin.IEnd(),
974 BEnd() + aMargin.BEnd(),
975 IStart() + aMargin.IStart());
978 LogicalMargin operator-(const LogicalMargin& aMargin) {
979 CHECK_WRITING_MODE(aMargin.GetWritingMode());
980 return LogicalMargin(GetWritingMode(),
981 BStart() - aMargin.BStart(),
982 IEnd() - aMargin.IEnd(),
983 BEnd() - aMargin.BEnd(),
984 IStart() - aMargin.IStart());
987 private:
988 friend class LogicalRect;
990 LogicalMargin() MOZ_DELETE;
992 #ifdef DEBUG
993 WritingMode GetWritingMode() const { return mWritingMode; }
994 #else
995 WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
996 #endif
998 nscoord IStart() const // inline-start margin
1000 return mMargin.left;
1002 nscoord IEnd() const // inline-end margin
1004 return mMargin.right;
1006 nscoord BStart() const // block-start margin
1008 return mMargin.top;
1010 nscoord BEnd() const // block-end margin
1012 return mMargin.bottom;
1015 nscoord& IStart() // inline-start margin
1017 return mMargin.left;
1019 nscoord& IEnd() // inline-end margin
1021 return mMargin.right;
1023 nscoord& BStart() // block-start margin
1025 return mMargin.top;
1027 nscoord& BEnd() // block-end margin
1029 return mMargin.bottom;
1032 nscoord IStartEnd() const // inline margins
1034 return mMargin.LeftRight();
1036 nscoord BStartEnd() const // block margins
1038 return mMargin.TopBottom();
1041 WritingMode mWritingMode;
1042 nsMargin mMargin;
1046 * Flow-relative rectangle
1048 class LogicalRect {
1049 public:
1050 explicit LogicalRect(WritingMode aWritingMode)
1052 #ifdef DEBUG
1053 mWritingMode(aWritingMode),
1054 #endif
1055 mRect(0, 0, 0, 0)
1058 LogicalRect(WritingMode aWritingMode,
1059 nscoord aIStart, nscoord aBStart,
1060 nscoord aISize, nscoord aBSize)
1062 #ifdef DEBUG
1063 mWritingMode(aWritingMode),
1064 #endif
1065 mRect(aIStart, aBStart, aISize, aBSize)
1068 LogicalRect(WritingMode aWritingMode,
1069 const LogicalPoint& aOrigin,
1070 const LogicalSize& aSize)
1072 #ifdef DEBUG
1073 mWritingMode(aWritingMode),
1074 #endif
1075 mRect(aOrigin.mPoint, aSize.mSize)
1077 CHECK_WRITING_MODE(aOrigin.GetWritingMode());
1078 CHECK_WRITING_MODE(aSize.GetWritingMode());
1081 LogicalRect(WritingMode aWritingMode,
1082 const nsRect& aRect,
1083 nscoord aContainerWidth)
1084 #ifdef DEBUG
1085 : mWritingMode(aWritingMode)
1086 #endif
1088 if (aWritingMode.IsVertical()) {
1089 if (aWritingMode.IsVerticalLR()) {
1090 mRect.y = aRect.x;
1091 } else {
1092 mRect.y = aContainerWidth - aRect.XMost();
1094 mRect.height = aRect.width;
1095 mRect.x = aRect.y;
1096 mRect.width = aRect.height;
1097 } else {
1098 if (aWritingMode.IsBidiLTR()) {
1099 mRect.x = aRect.x;
1100 } else {
1101 mRect.x = aContainerWidth - aRect.XMost();
1103 mRect.width = aRect.width;
1104 mRect.y = aRect.y;
1105 mRect.height = aRect.height;
1110 * Inline- and block-dimension geometry.
1112 nscoord IStart(WritingMode aWritingMode) const // inline-start edge
1114 CHECK_WRITING_MODE(aWritingMode);
1115 return mRect.X();
1117 nscoord IEnd(WritingMode aWritingMode) const // inline-end edge
1119 CHECK_WRITING_MODE(aWritingMode);
1120 return mRect.XMost();
1122 nscoord ISize(WritingMode aWritingMode) const // inline-size
1124 CHECK_WRITING_MODE(aWritingMode);
1125 return mRect.Width();
1128 nscoord BStart(WritingMode aWritingMode) const // block-start edge
1130 CHECK_WRITING_MODE(aWritingMode);
1131 return mRect.Y();
1133 nscoord BEnd(WritingMode aWritingMode) const // block-end edge
1135 CHECK_WRITING_MODE(aWritingMode);
1136 return mRect.YMost();
1138 nscoord BSize(WritingMode aWritingMode) const // block-size
1140 CHECK_WRITING_MODE(aWritingMode);
1141 return mRect.Height();
1145 * Writable (reference) accessors are only available for the basic logical
1146 * fields (Start and Size), not derivatives like End.
1148 nscoord& IStart(WritingMode aWritingMode) // inline-start edge
1150 CHECK_WRITING_MODE(aWritingMode);
1151 return mRect.x;
1153 nscoord& ISize(WritingMode aWritingMode) // inline-size
1155 CHECK_WRITING_MODE(aWritingMode);
1156 return mRect.width;
1158 nscoord& BStart(WritingMode aWritingMode) // block-start edge
1160 CHECK_WRITING_MODE(aWritingMode);
1161 return mRect.y;
1163 nscoord& BSize(WritingMode aWritingMode) // block-size
1165 CHECK_WRITING_MODE(aWritingMode);
1166 return mRect.height;
1170 * Physical coordinates of the rect.
1172 nscoord X(WritingMode aWritingMode, nscoord aContainerWidth) const
1174 CHECK_WRITING_MODE(aWritingMode);
1175 if (aWritingMode.IsVertical()) {
1176 return aWritingMode.IsVerticalLR() ?
1177 mRect.Y() : aContainerWidth - mRect.YMost();
1178 } else {
1179 return aWritingMode.IsBidiLTR() ?
1180 mRect.X() : aContainerWidth - mRect.XMost();
1184 void SetX(WritingMode aWritingMode, nscoord aX, nscoord aContainerWidth)
1186 CHECK_WRITING_MODE(aWritingMode);
1187 if (aWritingMode.IsVertical()) {
1188 if (aWritingMode.IsVerticalLR()) {
1189 BStart() = aX;
1190 } else {
1191 BStart() = aContainerWidth - aX - BSize();
1193 } else {
1194 if (aWritingMode.IsBidiLTR()) {
1195 IStart() = aX;
1196 } else {
1197 IStart() = aContainerWidth - aX - ISize();
1202 nscoord Y(WritingMode aWritingMode) const
1204 CHECK_WRITING_MODE(aWritingMode);
1205 return aWritingMode.IsVertical() ? mRect.X() : mRect.Y();
1208 void SetY(WritingMode aWritingMode, nscoord aY)
1210 CHECK_WRITING_MODE(aWritingMode);
1211 if (aWritingMode.IsVertical()) {
1212 IStart() = aY;
1213 } else {
1214 BStart() = aY;
1218 nscoord Width(WritingMode aWritingMode) const
1220 CHECK_WRITING_MODE(aWritingMode);
1221 return aWritingMode.IsVertical() ? mRect.Height() : mRect.Width();
1224 // When setting the Width of a rect, we keep its physical X-coord fixed
1225 // and modify XMax. This means that in the RTL case, we'll be moving
1226 // the IStart, so that IEnd remains constant.
1227 void SetWidth(WritingMode aWritingMode, nscoord aWidth)
1229 CHECK_WRITING_MODE(aWritingMode);
1230 if (aWritingMode.IsVertical()) {
1231 if (!aWritingMode.IsVerticalLR()) {
1232 BStart() = BStart() + BSize() - aWidth;
1234 BSize() = aWidth;
1235 } else {
1236 if (!aWritingMode.IsBidiLTR()) {
1237 IStart() = IStart() + ISize() - aWidth;
1239 ISize() = aWidth;
1243 nscoord Height(WritingMode aWritingMode) const
1245 CHECK_WRITING_MODE(aWritingMode);
1246 return aWritingMode.IsVertical() ? mRect.Width() : mRect.Height();
1249 void SetHeight(WritingMode aWritingMode, nscoord aHeight)
1251 CHECK_WRITING_MODE(aWritingMode);
1252 if (aWritingMode.IsVertical()) {
1253 ISize() = aHeight;
1254 } else {
1255 BSize() = aHeight;
1259 nscoord XMost(WritingMode aWritingMode, nscoord aContainerWidth) const
1261 CHECK_WRITING_MODE(aWritingMode);
1262 if (aWritingMode.IsVertical()) {
1263 return aWritingMode.IsVerticalLR() ?
1264 mRect.YMost() : aContainerWidth - mRect.Y();
1265 } else {
1266 return aWritingMode.IsBidiLTR() ?
1267 mRect.XMost() : aContainerWidth - mRect.X();
1271 nscoord YMost(WritingMode aWritingMode) const
1273 CHECK_WRITING_MODE(aWritingMode);
1274 return aWritingMode.IsVertical() ? mRect.XMost() : mRect.YMost();
1277 bool IsEmpty() const
1279 return (mRect.x == 0 && mRect.y == 0 &&
1280 mRect.width == 0 && mRect.height == 0);
1283 bool IsZeroSize() const
1285 return (mRect.width == 0 && mRect.height == 0);
1288 void SetEmpty() { mRect.SetEmpty(); }
1290 /* XXX are these correct?
1291 nscoord ILeft(WritingMode aWritingMode) const
1293 CHECK_WRITING_MODE(aWritingMode);
1294 return aWritingMode.IsBidiLTR() ? IStart() : IEnd();
1296 nscoord IRight(WritingMode aWritingMode) const
1298 CHECK_WRITING_MODE(aWritingMode);
1299 return aWritingMode.IsBidiLTR() ? IEnd() : IStart();
1303 LogicalPoint Origin(WritingMode aWritingMode) const
1305 CHECK_WRITING_MODE(aWritingMode);
1306 return LogicalPoint(aWritingMode, IStart(), BStart());
1308 LogicalSize Size(WritingMode aWritingMode) const
1310 CHECK_WRITING_MODE(aWritingMode);
1311 return LogicalSize(aWritingMode, ISize(), BSize());
1314 LogicalRect operator+(const LogicalPoint& aPoint) const
1316 CHECK_WRITING_MODE(aPoint.GetWritingMode());
1317 return LogicalRect(GetWritingMode(),
1318 IStart() + aPoint.I(), BStart() + aPoint.B(),
1319 ISize(), BSize());
1322 LogicalRect& operator+=(const LogicalPoint& aPoint)
1324 CHECK_WRITING_MODE(aPoint.GetWritingMode());
1325 mRect += aPoint.mPoint;
1326 return *this;
1329 LogicalRect operator-(const LogicalPoint& aPoint) const
1331 CHECK_WRITING_MODE(aPoint.GetWritingMode());
1332 return LogicalRect(GetWritingMode(),
1333 IStart() - aPoint.I(), BStart() - aPoint.B(),
1334 ISize(), BSize());
1337 LogicalRect& operator-=(const LogicalPoint& aPoint)
1339 CHECK_WRITING_MODE(aPoint.GetWritingMode());
1340 mRect -= aPoint.mPoint;
1341 return *this;
1344 void MoveBy(WritingMode aWritingMode, const LogicalPoint& aDelta)
1346 CHECK_WRITING_MODE(aWritingMode);
1347 CHECK_WRITING_MODE(aDelta.GetWritingMode());
1348 IStart() += aDelta.I();
1349 BStart() += aDelta.B();
1352 void Inflate(nscoord aD) { mRect.Inflate(aD); }
1353 void Inflate(nscoord aDI, nscoord aDB) { mRect.Inflate(aDI, aDB); }
1354 void Inflate(WritingMode aWritingMode, const LogicalMargin& aMargin)
1356 CHECK_WRITING_MODE(aWritingMode);
1357 CHECK_WRITING_MODE(aMargin.GetWritingMode());
1358 mRect.Inflate(aMargin.mMargin);
1361 void Deflate(nscoord aD) { mRect.Deflate(aD); }
1362 void Deflate(nscoord aDI, nscoord aDB) { mRect.Deflate(aDI, aDB); }
1363 void Deflate(WritingMode aWritingMode, const LogicalMargin& aMargin)
1365 CHECK_WRITING_MODE(aWritingMode);
1366 CHECK_WRITING_MODE(aMargin.GetWritingMode());
1367 mRect.Deflate(aMargin.mMargin);
1371 * Return an nsRect containing our physical coordinates within the given
1372 * container width
1374 nsRect GetPhysicalRect(WritingMode aWritingMode,
1375 nscoord aContainerWidth) const
1377 CHECK_WRITING_MODE(aWritingMode);
1378 if (aWritingMode.IsVertical()) {
1379 return nsRect(aWritingMode.IsVerticalLR() ?
1380 BStart() : aContainerWidth - BEnd(),
1381 IStart(), BSize(), ISize());
1382 } else {
1383 return nsRect(aWritingMode.IsBidiLTR() ?
1384 IStart() : aContainerWidth - IEnd(),
1385 BStart(), ISize(), BSize());
1389 nsPoint GetPhysicalPosition(WritingMode aWritingMode,
1390 nscoord aContainerWidth) const
1392 CHECK_WRITING_MODE(aWritingMode);
1393 if (aWritingMode.IsVertical()) {
1394 return nsPoint(aWritingMode.IsVerticalLR() ? BStart() : aContainerWidth - BEnd(),
1395 IStart());
1396 } else {
1397 return nsPoint(aWritingMode.IsBidiLTR() ? IStart() : aContainerWidth - IEnd(),
1398 BStart());
1402 #if 0 // XXX this would require aContainerWidth as well
1404 * Return a LogicalRect representing this rect in a different writing mode
1406 LogicalRect ConvertTo(WritingMode aToMode, WritingMode aFromMode) const
1408 CHECK_WRITING_MODE(aFromMode);
1409 return aToMode == aFromMode ?
1410 *this : LogicalRect(aToMode, GetPhysicalRect(aFromMode));
1412 #endif
1414 private:
1415 LogicalRect() MOZ_DELETE;
1417 #ifdef DEBUG
1418 WritingMode GetWritingMode() const { return mWritingMode; }
1419 #else
1420 WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
1421 #endif
1423 nscoord IStart() const // inline-start edge
1425 return mRect.X();
1427 nscoord IEnd() const // inline-end edge
1429 return mRect.XMost();
1431 nscoord ISize() const // inline-size
1433 return mRect.Width();
1436 nscoord BStart() const // block-start edge
1438 return mRect.Y();
1440 nscoord BEnd() const // block-end edge
1442 return mRect.YMost();
1444 nscoord BSize() const // block-size
1446 return mRect.Height();
1449 nscoord& IStart() // inline-start edge
1451 return mRect.x;
1453 nscoord& ISize() // inline-size
1455 return mRect.width;
1457 nscoord& BStart() // block-start edge
1459 return mRect.y;
1461 nscoord& BSize() // block-size
1463 return mRect.height;
1466 WritingMode mWritingMode;
1467 nsRect mRect;
1470 } // namespace mozilla
1472 #endif // WritingModes_h_