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_
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")
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
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");
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
;
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
);
106 * mozilla::WritingMode is an immutable class representing a
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/
120 * Absolute inline flow direction
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
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
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).
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
); }
185 bool IsVertical() const { return false; }
189 * True if line-over/line-under are inverted from block-start/block-end.
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
); }
197 bool IsLineInverted() const { return false; }
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.
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
:
233 case NS_STYLE_WRITING_MODE_VERTICAL_LR
:
234 mWritingMode
= eBlockFlowMask
|
235 eLineOrientMask
| //XXX needs update when text-orientation added
239 case NS_STYLE_WRITING_MODE_VERTICAL_RL
:
240 mWritingMode
= eOrientationMask
;
244 NS_NOTREACHED("unknown writing mode!");
252 if (NS_STYLE_DIRECTION_RTL
== aStyleVisibility
->mDirection
) {
253 mWritingMode
|= eInlineFlowMask
| //XXX needs update when text-orientation added
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
)
265 // odd level, set RTL
266 mWritingMode
|= eBidiMask
;
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
;
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
;
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
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)
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
368 explicit LogicalPoint(WritingMode aWritingMode
)
371 mWritingMode(aWritingMode
),
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
)
381 mWritingMode(aWritingMode
),
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
)
393 : mWritingMode(aWritingMode
)
396 if (aWritingMode
.IsVertical()) {
398 B() = aWritingMode
.IsVerticalLR() ? aPoint
.x
: aContainerWidth
- aPoint
.x
;
400 I() = aWritingMode
.IsBidiLTR() ? aPoint
.x
: aContainerWidth
- aPoint
.x
;
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
);
414 nscoord
B(WritingMode aWritingMode
) const // block-axis
416 CHECK_WRITING_MODE(aWritingMode
);
420 nscoord
X(WritingMode aWritingMode
, nscoord aContainerWidth
) const
422 CHECK_WRITING_MODE(aWritingMode
);
423 if (aWritingMode
.IsVertical()) {
424 return aWritingMode
.IsVerticalLR() ? B() : aContainerWidth
- B();
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
);
444 nscoord
& B(WritingMode aWritingMode
) // block-axis
446 CHECK_WRITING_MODE(aWritingMode
);
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
;
459 I() = aWritingMode
.IsBidiLTR() ? aX
: aContainerWidth
- aX
;
462 void SetY(WritingMode aWritingMode
, nscoord aY
)
464 CHECK_WRITING_MODE(aWritingMode
);
465 if (aWritingMode
.IsVertical()) {
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(),
484 return nsPoint(aWritingMode
.IsBidiLTR() ? I() : aContainerWidth
- I(),
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
),
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)
508 return LogicalPoint(GetWritingMode(),
509 mPoint
.x
+ aOther
.mPoint
.x
,
510 mPoint
.y
+ aOther
.mPoint
.y
);
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
529 WritingMode
GetWritingMode() const { return mWritingMode
; }
531 WritingMode
GetWritingMode() const { return WritingMode::Unknown(); }
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
544 nscoord
B() const // block-axis
549 nscoord
& I() // inline-axis
553 nscoord
& B() // block-axis
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
572 explicit LogicalSize(WritingMode aWritingMode
)
575 mWritingMode(aWritingMode
),
580 LogicalSize(WritingMode aWritingMode
, nscoord aISize
, nscoord aBSize
)
583 mWritingMode(aWritingMode
),
585 mSize(aISize
, aBSize
)
588 LogicalSize(WritingMode aWritingMode
, const nsSize
& aPhysicalSize
)
590 : mWritingMode(aWritingMode
)
593 if (aWritingMode
.IsVertical()) {
594 ISize() = aPhysicalSize
.height
;
595 BSize() = aPhysicalSize
.width
;
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
);
616 nscoord
BSize(WritingMode aWritingMode
) const // block-size
618 CHECK_WRITING_MODE(aWritingMode
);
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
);
641 nscoord
& BSize(WritingMode aWritingMode
) // block-size
643 CHECK_WRITING_MODE(aWritingMode
);
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();
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();
717 friend class LogicalRect
;
719 LogicalSize() MOZ_DELETE
;
722 WritingMode
GetWritingMode() const { return mWritingMode
; }
724 WritingMode
GetWritingMode() const { return WritingMode::Unknown(); }
727 nscoord
ISize() const // inline-size
731 nscoord
BSize() const // block-size
736 nscoord
& ISize() // inline-size
740 nscoord
& BSize() // block-size
745 WritingMode mWritingMode
;
750 * Flow-relative margin
752 class LogicalMargin
{
754 explicit LogicalMargin(WritingMode aWritingMode
)
757 mWritingMode(aWritingMode
),
762 LogicalMargin(WritingMode aWritingMode
,
763 nscoord aBStart
, nscoord aIEnd
,
764 nscoord aBEnd
, nscoord aIStart
)
767 mWritingMode(aWritingMode
),
769 mMargin(aBStart
, aIEnd
, aBEnd
, aIStart
)
772 LogicalMargin(WritingMode aWritingMode
, const nsMargin
& aPhysicalMargin
)
774 : mWritingMode(aWritingMode
)
777 if (aWritingMode
.IsVertical()) {
778 if (aWritingMode
.IsVerticalLR()) {
779 mMargin
.top
= aPhysicalMargin
.left
;
780 mMargin
.bottom
= aPhysicalMargin
.right
;
782 mMargin
.top
= aPhysicalMargin
.right
;
783 mMargin
.bottom
= aPhysicalMargin
.left
;
785 if (aWritingMode
.IsBidiLTR()) {
786 mMargin
.left
= aPhysicalMargin
.top
;
787 mMargin
.right
= aPhysicalMargin
.bottom
;
789 mMargin
.left
= aPhysicalMargin
.bottom
;
790 mMargin
.right
= aPhysicalMargin
.top
;
793 mMargin
.top
= aPhysicalMargin
.top
;
794 mMargin
.bottom
= aPhysicalMargin
.bottom
;
795 if (aWritingMode
.IsBidiLTR()) {
796 mMargin
.left
= aPhysicalMargin
.left
;
797 mMargin
.right
= aPhysicalMargin
.right
;
799 mMargin
.left
= aPhysicalMargin
.right
;
800 mMargin
.right
= aPhysicalMargin
.left
;
805 nscoord
IStart(WritingMode aWritingMode
) const // inline-start margin
807 CHECK_WRITING_MODE(aWritingMode
);
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
);
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
);
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
);
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
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
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()) {
952 if (aSkipSides
.BEnd()) {
955 if (aSkipSides
.IStart()) {
958 if (aSkipSides
.IEnd()) {
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());
988 friend class LogicalRect
;
990 LogicalMargin() MOZ_DELETE
;
993 WritingMode
GetWritingMode() const { return mWritingMode
; }
995 WritingMode
GetWritingMode() const { return WritingMode::Unknown(); }
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
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
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
;
1046 * Flow-relative rectangle
1050 explicit LogicalRect(WritingMode aWritingMode
)
1053 mWritingMode(aWritingMode
),
1058 LogicalRect(WritingMode aWritingMode
,
1059 nscoord aIStart
, nscoord aBStart
,
1060 nscoord aISize
, nscoord aBSize
)
1063 mWritingMode(aWritingMode
),
1065 mRect(aIStart
, aBStart
, aISize
, aBSize
)
1068 LogicalRect(WritingMode aWritingMode
,
1069 const LogicalPoint
& aOrigin
,
1070 const LogicalSize
& aSize
)
1073 mWritingMode(aWritingMode
),
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
)
1085 : mWritingMode(aWritingMode
)
1088 if (aWritingMode
.IsVertical()) {
1089 if (aWritingMode
.IsVerticalLR()) {
1092 mRect
.y
= aContainerWidth
- aRect
.XMost();
1094 mRect
.height
= aRect
.width
;
1096 mRect
.width
= aRect
.height
;
1098 if (aWritingMode
.IsBidiLTR()) {
1101 mRect
.x
= aContainerWidth
- aRect
.XMost();
1103 mRect
.width
= aRect
.width
;
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
);
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
);
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
);
1153 nscoord
& ISize(WritingMode aWritingMode
) // inline-size
1155 CHECK_WRITING_MODE(aWritingMode
);
1158 nscoord
& BStart(WritingMode aWritingMode
) // block-start edge
1160 CHECK_WRITING_MODE(aWritingMode
);
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();
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()) {
1191 BStart() = aContainerWidth
- aX
- BSize();
1194 if (aWritingMode
.IsBidiLTR()) {
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()) {
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
;
1236 if (!aWritingMode
.IsBidiLTR()) {
1237 IStart() = IStart() + 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()) {
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();
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(),
1322 LogicalRect
& operator+=(const LogicalPoint
& aPoint
)
1324 CHECK_WRITING_MODE(aPoint
.GetWritingMode());
1325 mRect
+= aPoint
.mPoint
;
1329 LogicalRect
operator-(const LogicalPoint
& aPoint
) const
1331 CHECK_WRITING_MODE(aPoint
.GetWritingMode());
1332 return LogicalRect(GetWritingMode(),
1333 IStart() - aPoint
.I(), BStart() - aPoint
.B(),
1337 LogicalRect
& operator-=(const LogicalPoint
& aPoint
)
1339 CHECK_WRITING_MODE(aPoint
.GetWritingMode());
1340 mRect
-= aPoint
.mPoint
;
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
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());
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(),
1397 return nsPoint(aWritingMode
.IsBidiLTR() ? IStart() : aContainerWidth
- IEnd(),
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
));
1415 LogicalRect() MOZ_DELETE
;
1418 WritingMode
GetWritingMode() const { return mWritingMode
; }
1420 WritingMode
GetWritingMode() const { return WritingMode::Unknown(); }
1423 nscoord
IStart() const // inline-start edge
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
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
1453 nscoord
& ISize() // inline-size
1457 nscoord
& BStart() // block-start edge
1461 nscoord
& BSize() // block-size
1463 return mRect
.height
;
1466 WritingMode mWritingMode
;
1470 } // namespace mozilla
1472 #endif // WritingModes_h_