1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef WritingModes_h_
8 #define WritingModes_h_
12 #include "mozilla/intl/BidiEmbeddingLevel.h"
13 #include "mozilla/ComputedStyle.h"
14 #include "mozilla/EnumeratedRange.h"
17 #include "nsBidiUtils.h"
18 #include "nsStyleStruct.h"
20 // It is the caller's responsibility to operate on logical-coordinate objects
21 // with matched writing modes. Failure to do so will be a runtime bug; the
22 // compiler can't catch it, but in debug mode, we'll throw an assertion.
23 // NOTE that in non-debug builds, a writing mode mismatch error will NOT be
24 // detected, yet the results will be nonsense (and may lead to further layout
25 // failures). Therefore, it is important to test (and fuzz-test) writing-mode
26 // support using debug builds.
28 // Methods in logical-coordinate classes that take another logical-coordinate
29 // object as a parameter should call CHECK_WRITING_MODE on it to verify that
30 // the writing modes match.
31 // (In some cases, there are internal (private) methods that don't do this;
32 // such methods should only be used by other methods that have already checked
33 // the writing modes.)
34 // The check ignores the StyleWritingMode::VERTICAL_SIDEWAYS and
35 // StyleWritingMode::TEXT_SIDEWAYS bit of writing mode, because
36 // this does not affect the interpretation of logical coordinates.
38 #define CHECK_WRITING_MODE(param) \
39 NS_ASSERTION(param.IgnoreSideways() == GetWritingMode().IgnoreSideways(), \
40 "writing-mode mismatch")
45 struct IMENotification
;
48 // Logical axis, edge, side and corner constants for use in various places.
49 enum LogicalAxis
: uint8_t {
50 eLogicalAxisBlock
= 0x0,
51 eLogicalAxisInline
= 0x1
53 enum LogicalEdge
{ eLogicalEdgeStart
= 0x0, eLogicalEdgeEnd
= 0x1 };
54 enum LogicalSide
: uint8_t {
55 eLogicalSideBStart
= (eLogicalAxisBlock
<< 1) | eLogicalEdgeStart
, // 0x0
56 eLogicalSideBEnd
= (eLogicalAxisBlock
<< 1) | eLogicalEdgeEnd
, // 0x1
57 eLogicalSideIStart
= (eLogicalAxisInline
<< 1) | eLogicalEdgeStart
, // 0x2
58 eLogicalSideIEnd
= (eLogicalAxisInline
<< 1) | eLogicalEdgeEnd
// 0x3
60 constexpr auto AllLogicalSides() {
61 return mozilla::MakeInclusiveEnumeratedRange(eLogicalSideBStart
,
66 eLogicalCornerBStartIStart
= 0,
67 eLogicalCornerBStartIEnd
= 1,
68 eLogicalCornerBEndIEnd
= 2,
69 eLogicalCornerBEndIStart
= 3
72 // Physical axis constants.
73 enum PhysicalAxis
{ eAxisVertical
= 0x0, eAxisHorizontal
= 0x1 };
75 // Represents zero or more physical axes.
76 enum class PhysicalAxes
: uint8_t {
80 Both
= Horizontal
| Vertical
,
82 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(PhysicalAxes
)
84 inline LogicalAxis
GetOrthogonalAxis(LogicalAxis aAxis
) {
85 return aAxis
== eLogicalAxisBlock
? eLogicalAxisInline
: eLogicalAxisBlock
;
88 inline bool IsInline(LogicalSide aSide
) { return aSide
& 0x2; }
89 inline bool IsBlock(LogicalSide aSide
) { return !IsInline(aSide
); }
90 inline bool IsEnd(LogicalSide aSide
) { return aSide
& 0x1; }
91 inline bool IsStart(LogicalSide aSide
) { return !IsEnd(aSide
); }
93 inline LogicalAxis
GetAxis(LogicalSide aSide
) {
94 return IsInline(aSide
) ? eLogicalAxisInline
: eLogicalAxisBlock
;
97 inline LogicalEdge
GetEdge(LogicalSide aSide
) {
98 return IsEnd(aSide
) ? eLogicalEdgeEnd
: eLogicalEdgeStart
;
101 inline LogicalEdge
GetOppositeEdge(LogicalEdge aEdge
) {
102 // This relies on the only two LogicalEdge enum values being 0 and 1.
103 return LogicalEdge(1 - aEdge
);
106 inline LogicalSide
MakeLogicalSide(LogicalAxis aAxis
, LogicalEdge aEdge
) {
107 return LogicalSide((aAxis
<< 1) | aEdge
);
110 inline LogicalSide
GetOppositeSide(LogicalSide aSide
) {
111 return MakeLogicalSide(GetAxis(aSide
), GetOppositeEdge(GetEdge(aSide
)));
114 enum LogicalSideBits
{
115 eLogicalSideBitsNone
= 0,
116 eLogicalSideBitsBStart
= 1 << eLogicalSideBStart
,
117 eLogicalSideBitsBEnd
= 1 << eLogicalSideBEnd
,
118 eLogicalSideBitsIEnd
= 1 << eLogicalSideIEnd
,
119 eLogicalSideBitsIStart
= 1 << eLogicalSideIStart
,
120 eLogicalSideBitsBBoth
= eLogicalSideBitsBStart
| eLogicalSideBitsBEnd
,
121 eLogicalSideBitsIBoth
= eLogicalSideBitsIStart
| eLogicalSideBitsIEnd
,
122 eLogicalSideBitsAll
= eLogicalSideBitsBBoth
| eLogicalSideBitsIBoth
125 enum LineRelativeDir
{
126 eLineRelativeDirOver
= eLogicalSideBStart
,
127 eLineRelativeDirUnder
= eLogicalSideBEnd
,
128 eLineRelativeDirLeft
= eLogicalSideIStart
,
129 eLineRelativeDirRight
= eLogicalSideIEnd
133 * mozilla::WritingMode is an immutable class representing a
136 * It efficiently stores the writing mode and can rapidly compute
137 * interesting things about it for use in layout.
139 * Writing modes are computed from the CSS 'direction',
140 * 'writing-mode', and 'text-orientation' properties.
141 * See CSS3 Writing Modes for more information
142 * http://www.w3.org/TR/css3-writing-modes/
147 * Absolute inline flow direction
150 eInlineLTR
= 0x00, // text flows horizontally left to right
151 eInlineRTL
= 0x02, // text flows horizontally right to left
152 eInlineTTB
= 0x01, // text flows vertically top to bottom
153 eInlineBTT
= 0x03, // text flows vertically bottom to top
157 * Absolute block flow direction
160 eBlockTB
= 0x00, // horizontal lines stack top to bottom
161 eBlockRL
= 0x01, // vertical lines stack right to left
162 eBlockLR
= 0x05, // vertical lines stack left to right
166 * Line-relative (bidi-relative) inline flow direction
169 eBidiLTR
= 0x00, // inline flow matches bidi LTR text
170 eBidiRTL
= 0x10, // inline flow matches bidi RTL text
174 * Unknown writing mode (should never actually be stored or used anywhere).
176 enum { eUnknownWritingMode
= 0xff };
179 * Return the absolute inline flow direction as an InlineDir
181 InlineDir
GetInlineDir() const {
182 return InlineDir(mWritingMode
._0
& eInlineMask
);
186 * Return the absolute block flow direction as a BlockDir
188 BlockDir
GetBlockDir() const {
189 return BlockDir(mWritingMode
._0
& eBlockMask
);
193 * Return the line-relative inline flow direction as a BidiDir
195 BidiDir
GetBidiDir() const {
196 return BidiDir((mWritingMode
& StyleWritingMode::RTL
)._0
);
200 * Return true if the inline flow direction is against physical direction
201 * (i.e. right-to-left or bottom-to-top).
202 * This occurs when writing-mode is sideways-lr OR direction is rtl (but not
203 * if both of those are true).
205 bool IsInlineReversed() const {
206 return !!(mWritingMode
& StyleWritingMode::INLINE_REVERSED
);
210 * Return true if bidi direction is LTR. (Convenience method)
212 bool IsBidiLTR() const { return eBidiLTR
== GetBidiDir(); }
215 * Return true if bidi direction is RTL. (Convenience method)
217 bool IsBidiRTL() const { return eBidiRTL
== GetBidiDir(); }
220 * True if it is vertical and vertical-lr, or is horizontal and bidi LTR.
222 bool IsPhysicalLTR() const {
223 return IsVertical() ? IsVerticalLR() : IsBidiLTR();
227 * True if it is vertical and vertical-rl, or is horizontal and bidi RTL.
229 bool IsPhysicalRTL() const {
230 return IsVertical() ? IsVerticalRL() : IsBidiRTL();
234 * True if vertical-mode block direction is LR (convenience method).
236 bool IsVerticalLR() const { return eBlockLR
== GetBlockDir(); }
239 * True if vertical-mode block direction is RL (convenience method).
241 bool IsVerticalRL() const { return eBlockRL
== GetBlockDir(); }
244 * True if vertical writing mode, i.e. when
245 * writing-mode: vertical-lr | vertical-rl.
247 bool IsVertical() const {
248 return !!(mWritingMode
& StyleWritingMode::VERTICAL
);
252 * True if line-over/line-under are inverted from block-start/block-end.
253 * This is true only when writing-mode is vertical-lr.
255 bool IsLineInverted() const {
256 return !!(mWritingMode
& StyleWritingMode::LINE_INVERTED
);
260 * Block-axis flow-relative to line-relative factor.
261 * May be used as a multiplication factor for block-axis coordinates
262 * to convert between flow- and line-relative coordinate systems (e.g.
263 * positioning an over- or under-line decoration).
265 int FlowRelativeToLineRelativeFactor() const {
266 return IsLineInverted() ? -1 : 1;
270 * True if vertical sideways writing mode, i.e. when
271 * writing-mode: sideways-lr | sideways-rl.
273 bool IsVerticalSideways() const {
274 return !!(mWritingMode
& StyleWritingMode::VERTICAL_SIDEWAYS
);
278 * True if this is writing-mode: sideways-rl (convenience method).
280 bool IsSidewaysRL() const { return IsVerticalRL() && IsVerticalSideways(); }
283 * True if this is writing-mode: sideways-lr (convenience method).
285 bool IsSidewaysLR() const { return IsVerticalLR() && IsVerticalSideways(); }
288 * True if either text-orientation or writing-mode will force all text to be
289 * rendered sideways in vertical lines, in which case we should prefer an
290 * alphabetic baseline; otherwise, the default is centered.
292 * Note that some glyph runs may be rendered sideways even if this is false,
293 * due to text-orientation:mixed resolution, but in that case the dominant
294 * baseline remains centered.
296 bool IsSideways() const {
297 return !!(mWritingMode
& (StyleWritingMode::VERTICAL_SIDEWAYS
|
298 StyleWritingMode::TEXT_SIDEWAYS
));
302 // Used by CHECK_WRITING_MODE to compare modes without regard for the
303 // StyleWritingMode::VERTICAL_SIDEWAYS or StyleWritingMode::TEXT_SIDEWAYS
305 WritingMode
IgnoreSideways() const {
306 return WritingMode(mWritingMode
._0
& ~(StyleWritingMode::VERTICAL_SIDEWAYS
|
307 StyleWritingMode::TEXT_SIDEWAYS
)
313 * Return true if boxes with this writing mode should use central baselines.
315 bool IsCentralBaseline() const { return IsVertical() && !IsSideways(); }
318 * Return true if boxes with this writing mode should use alphabetical
321 bool IsAlphabeticalBaseline() const { return !IsCentralBaseline(); }
323 static mozilla::PhysicalAxis
PhysicalAxisForLogicalAxis(
324 uint8_t aWritingModeValue
, LogicalAxis aAxis
) {
325 // This relies on bit 0 of a writing-value mode indicating vertical
326 // orientation and bit 0 of a LogicalAxis value indicating the inline axis,
327 // so that it can correctly form mozilla::PhysicalAxis values using bit
329 static_assert(uint8_t(StyleWritingModeProperty::HorizontalTb
) == 0 &&
330 uint8_t(StyleWritingModeProperty::VerticalRl
) == 1 &&
331 uint8_t(StyleWritingModeProperty::VerticalLr
) == 3 &&
332 eLogicalAxisBlock
== 0 && eLogicalAxisInline
== 1 &&
333 eAxisVertical
== 0 && eAxisHorizontal
== 1,
334 "unexpected writing-mode, logical axis or physical axis "
336 return mozilla::PhysicalAxis((aWritingModeValue
^ aAxis
) & 0x1);
339 mozilla::PhysicalAxis
PhysicalAxis(LogicalAxis aAxis
) const {
340 // This will set wm to either StyleWritingModel::HorizontalTB or
341 // StyleWritingModeProperty::VerticalRL, and not the other two (real
342 // and hypothetical) values. But this is fine; we only need to
343 // distinguish between vertical and horizontal in
344 // PhysicalAxisForLogicalAxis.
345 const auto wm
= (mWritingMode
& StyleWritingMode::VERTICAL
)._0
;
346 return PhysicalAxisForLogicalAxis(wm
, aAxis
);
349 static mozilla::Side
PhysicalSideForBlockAxis(uint8_t aWritingModeValue
,
351 // indexes are StyleWritingModeProperty values, which are the same as these
353 // bit 0 = the StyleWritingMode::VERTICAL value
354 // bit 1 = the StyleWritingMode::VERTICAL_LR value
355 static const mozilla::Side kLogicalBlockSides
[][2] = {
356 {eSideTop
, eSideBottom
}, // horizontal-tb
357 {eSideRight
, eSideLeft
}, // vertical-rl
358 {eSideBottom
, eSideTop
}, // (horizontal-bt)
359 {eSideLeft
, eSideRight
}, // vertical-lr
362 // Ignore the SidewaysMask bit of the writing-mode value, as this has no
363 // effect on the side mappings.
364 aWritingModeValue
&= ~kWritingModeSidewaysMask
;
366 // What's left of the writing-mode should be in the range 0-3:
367 NS_ASSERTION(aWritingModeValue
< 4, "invalid aWritingModeValue value");
369 return kLogicalBlockSides
[aWritingModeValue
][aEdge
];
372 mozilla::Side
PhysicalSideForInlineAxis(LogicalEdge aEdge
) const {
373 // indexes are four-bit values:
374 // bit 0 = the StyleWritingMode::VERTICAL value
375 // bit 1 = the StyleWritingMode::INLINE_REVERSED value
376 // bit 2 = the StyleWritingMode::VERTICAL_LR value
377 // bit 3 = the StyleWritingMode::LINE_INVERTED value
378 // Not all of these combinations can actually be specified via CSS: there
379 // is no horizontal-bt writing-mode, and no text-orientation value that
380 // produces "inverted" text. (The former 'sideways-left' value, no longer
381 // in the spec, would have produced this in vertical-rl mode.)
382 static const mozilla::Side kLogicalInlineSides
[][2] = {
383 {eSideLeft
, eSideRight
}, // horizontal-tb ltr
384 {eSideTop
, eSideBottom
}, // vertical-rl ltr
385 {eSideRight
, eSideLeft
}, // horizontal-tb rtl
386 {eSideBottom
, eSideTop
}, // vertical-rl rtl
387 {eSideRight
, eSideLeft
}, // (horizontal-bt) (inverted) ltr
388 {eSideTop
, eSideBottom
}, // sideways-lr rtl
389 {eSideLeft
, eSideRight
}, // (horizontal-bt) (inverted) rtl
390 {eSideBottom
, eSideTop
}, // sideways-lr ltr
391 {eSideLeft
, eSideRight
}, // horizontal-tb (inverted) rtl
392 {eSideTop
, eSideBottom
}, // vertical-rl (inverted) rtl
393 {eSideRight
, eSideLeft
}, // horizontal-tb (inverted) ltr
394 {eSideBottom
, eSideTop
}, // vertical-rl (inverted) ltr
395 {eSideLeft
, eSideRight
}, // (horizontal-bt) ltr
396 {eSideTop
, eSideBottom
}, // vertical-lr ltr
397 {eSideRight
, eSideLeft
}, // (horizontal-bt) rtl
398 {eSideBottom
, eSideTop
}, // vertical-lr rtl
401 // Inline axis sides depend on all three of writing-mode, text-orientation
402 // and direction, which are encoded in the StyleWritingMode::VERTICAL,
403 // StyleWritingMode::INLINE_REVERSED, StyleWritingMode::VERTICAL_LR and
404 // StyleWritingMode::LINE_INVERTED bits. Use these four bits to index into
405 // kLogicalInlineSides.
406 MOZ_ASSERT(StyleWritingMode::VERTICAL
._0
== 0x01 &&
407 StyleWritingMode::INLINE_REVERSED
._0
== 0x02 &&
408 StyleWritingMode::VERTICAL_LR
._0
== 0x04 &&
409 StyleWritingMode::LINE_INVERTED
._0
== 0x08,
410 "unexpected mask values");
411 int index
= mWritingMode
._0
& 0x0F;
412 return kLogicalInlineSides
[index
][aEdge
];
416 * Returns the physical side corresponding to the specified logical side,
417 * given the current writing mode.
419 mozilla::Side
PhysicalSide(LogicalSide aSide
) const {
420 if (IsBlock(aSide
)) {
421 MOZ_ASSERT(StyleWritingMode::VERTICAL
._0
== 0x01 &&
422 StyleWritingMode::VERTICAL_LR
._0
== 0x04,
423 "unexpected mask values");
425 ((mWritingMode
& StyleWritingMode::VERTICAL_LR
)._0
>> 1) |
426 (mWritingMode
& StyleWritingMode::VERTICAL
)._0
;
427 return PhysicalSideForBlockAxis(wm
, GetEdge(aSide
));
430 return PhysicalSideForInlineAxis(GetEdge(aSide
));
434 * Returns the logical side corresponding to the specified physical side,
435 * given the current writing mode.
436 * (This is the inverse of the PhysicalSide() method above.)
438 LogicalSide
LogicalSideForPhysicalSide(mozilla::Side aSide
) const {
440 // indexes are four-bit values:
441 // bit 0 = the StyleWritingMode::VERTICAL value
442 // bit 1 = the StyleWritingMode::INLINE_REVERSED value
443 // bit 2 = the StyleWritingMode::VERTICAL_LR value
444 // bit 3 = the StyleWritingMode::LINE_INVERTED value
445 static const LogicalSide kPhysicalToLogicalSides
[][4] = {
448 { eLogicalSideBStart
, eLogicalSideIEnd
,
449 eLogicalSideBEnd
, eLogicalSideIStart
}, // horizontal-tb ltr
450 { eLogicalSideIStart
, eLogicalSideBStart
,
451 eLogicalSideIEnd
, eLogicalSideBEnd
}, // vertical-rl ltr
452 { eLogicalSideBStart
, eLogicalSideIStart
,
453 eLogicalSideBEnd
, eLogicalSideIEnd
}, // horizontal-tb rtl
454 { eLogicalSideIEnd
, eLogicalSideBStart
,
455 eLogicalSideIStart
, eLogicalSideBEnd
}, // vertical-rl rtl
456 { eLogicalSideBEnd
, eLogicalSideIStart
,
457 eLogicalSideBStart
, eLogicalSideIEnd
}, // (horizontal-bt) (inv) ltr
458 { eLogicalSideIStart
, eLogicalSideBEnd
,
459 eLogicalSideIEnd
, eLogicalSideBStart
}, // vertical-lr sw-left rtl
460 { eLogicalSideBEnd
, eLogicalSideIEnd
,
461 eLogicalSideBStart
, eLogicalSideIStart
}, // (horizontal-bt) (inv) rtl
462 { eLogicalSideIEnd
, eLogicalSideBEnd
,
463 eLogicalSideIStart
, eLogicalSideBStart
}, // vertical-lr sw-left ltr
464 { eLogicalSideBStart
, eLogicalSideIEnd
,
465 eLogicalSideBEnd
, eLogicalSideIStart
}, // horizontal-tb (inv) rtl
466 { eLogicalSideIStart
, eLogicalSideBStart
,
467 eLogicalSideIEnd
, eLogicalSideBEnd
}, // vertical-rl sw-left rtl
468 { eLogicalSideBStart
, eLogicalSideIStart
,
469 eLogicalSideBEnd
, eLogicalSideIEnd
}, // horizontal-tb (inv) ltr
470 { eLogicalSideIEnd
, eLogicalSideBStart
,
471 eLogicalSideIStart
, eLogicalSideBEnd
}, // vertical-rl sw-left ltr
472 { eLogicalSideBEnd
, eLogicalSideIEnd
,
473 eLogicalSideBStart
, eLogicalSideIStart
}, // (horizontal-bt) ltr
474 { eLogicalSideIStart
, eLogicalSideBEnd
,
475 eLogicalSideIEnd
, eLogicalSideBStart
}, // vertical-lr ltr
476 { eLogicalSideBEnd
, eLogicalSideIStart
,
477 eLogicalSideBStart
, eLogicalSideIEnd
}, // (horizontal-bt) rtl
478 { eLogicalSideIEnd
, eLogicalSideBEnd
,
479 eLogicalSideIStart
, eLogicalSideBStart
}, // vertical-lr rtl
483 MOZ_ASSERT(StyleWritingMode::VERTICAL
._0
== 0x01 &&
484 StyleWritingMode::INLINE_REVERSED
._0
== 0x02 &&
485 StyleWritingMode::VERTICAL_LR
._0
== 0x04 &&
486 StyleWritingMode::LINE_INVERTED
._0
== 0x08,
487 "unexpected mask values");
488 int index
= mWritingMode
._0
& 0x0F;
489 return kPhysicalToLogicalSides
[index
][aSide
];
493 * Returns the logical side corresponding to the specified
494 * line-relative direction, given the current writing mode.
496 LogicalSide
LogicalSideForLineRelativeDir(LineRelativeDir aDir
) const {
497 auto side
= static_cast<LogicalSide
>(aDir
);
498 if (IsInline(side
)) {
499 return IsBidiLTR() ? side
: GetOppositeSide(side
);
501 return !IsLineInverted() ? side
: GetOppositeSide(side
);
505 * Default constructor gives us a horizontal, LTR writing mode.
506 * XXX We will probably eliminate this and require explicit initialization
507 * in all cases once transition is complete.
509 WritingMode() : mWritingMode
{0} {}
512 * Construct writing mode based on a ComputedStyle.
514 explicit WritingMode(const ComputedStyle
* aComputedStyle
) {
515 NS_ASSERTION(aComputedStyle
, "we need an ComputedStyle here");
516 mWritingMode
= aComputedStyle
->WritingMode();
520 * This function performs fixup for elements with 'unicode-bidi: plaintext',
521 * where inline directionality is derived from the Unicode bidi categories
522 * of the element's content, and not the CSS 'direction' property.
524 * The WritingMode constructor will have already incorporated the 'direction'
525 * property into our flag bits, so such elements need to use this method
526 * (after resolving the bidi level of their content) to update the direction
529 * If it turns out that our bidi direction already matches what plaintext
530 * resolution determined, there's nothing to do here. If it didn't (i.e. if
531 * the rtl-ness doesn't match), then we correct the direction by flipping the
532 * same bits that get flipped in the constructor's CSS 'direction'-based
535 * XXX change uint8_t to UBiDiLevel after bug 924851
537 void SetDirectionFromBidiLevel(mozilla::intl::BidiEmbeddingLevel level
) {
538 if (level
.IsRTL() == IsBidiLTR()) {
539 mWritingMode
^= StyleWritingMode::RTL
| StyleWritingMode::INLINE_REVERSED
;
544 * Compare two WritingModes for equality.
546 bool operator==(const WritingMode
& aOther
) const {
547 return mWritingMode
== aOther
.mWritingMode
;
550 bool operator!=(const WritingMode
& aOther
) const {
551 return mWritingMode
!= aOther
.mWritingMode
;
555 * Check whether two modes are orthogonal to each other.
557 bool IsOrthogonalTo(const WritingMode
& aOther
) const {
558 return IsVertical() != aOther
.IsVertical();
562 * Returns true if this WritingMode's aLogicalAxis has the same physical
563 * start side as the parallel axis of WritingMode |aOther|.
565 * @param aLogicalAxis The axis to compare from this WritingMode.
566 * @param aOther The other WritingMode (from which we'll choose the axis
567 * that's parallel to this WritingMode's aLogicalAxis, for
570 bool ParallelAxisStartsOnSameSide(LogicalAxis aLogicalAxis
,
571 const WritingMode
& aOther
) const {
572 mozilla::Side myStartSide
=
573 this->PhysicalSide(MakeLogicalSide(aLogicalAxis
, eLogicalEdgeStart
));
575 // Figure out which of aOther's axes is parallel to |this| WritingMode's
576 // aLogicalAxis, and get its physical start side as well.
577 LogicalAxis otherWMAxis
= aOther
.IsOrthogonalTo(*this)
578 ? GetOrthogonalAxis(aLogicalAxis
)
580 mozilla::Side otherWMStartSide
=
581 aOther
.PhysicalSide(MakeLogicalSide(otherWMAxis
, eLogicalEdgeStart
));
583 NS_ASSERTION(myStartSide
% 2 == otherWMStartSide
% 2,
584 "Should end up with sides in the same physical axis");
585 return myStartSide
== otherWMStartSide
;
588 uint8_t GetBits() const { return mWritingMode
._0
; }
591 friend class LogicalPoint
;
592 friend class LogicalSize
;
593 friend struct LogicalSides
;
594 friend class LogicalMargin
;
595 friend class LogicalRect
;
597 friend struct IPC::ParamTraits
<WritingMode
>;
598 // IMENotification cannot store this class directly since this has some
599 // constructors. Therefore, it stores mWritingMode and recreate the
601 friend struct widget::IMENotification
;
604 * Return a WritingMode representing an unknown value.
606 static inline WritingMode
Unknown() {
607 return WritingMode(eUnknownWritingMode
);
611 * Constructing a WritingMode with an arbitrary value is a private operation
612 * currently only used by the Unknown() and IgnoreSideways() methods.
614 explicit WritingMode(uint8_t aValue
) : mWritingMode
{aValue
} {}
616 StyleWritingMode mWritingMode
;
619 // Masks for output enums
620 eInlineMask
= 0x03, // VERTICAL | INLINE_REVERSED
621 eBlockMask
= 0x05, // VERTICAL | VERTICAL_LR
625 inline std::ostream
& operator<<(std::ostream
& aStream
, const WritingMode
& aWM
) {
626 return aStream
<< (aWM
.IsVertical()
627 ? aWM
.IsVerticalLR() ? aWM
.IsBidiLTR()
631 : aWM
.IsSideways() ? "sw-lr-rtl"
634 ? aWM
.IsSideways() ? "sw-rl-ltr" : "v-rl-ltr"
635 : aWM
.IsSideways() ? "sw-rl-rtl"
637 : aWM
.IsBidiLTR() ? "h-ltr"
642 * Logical-coordinate classes:
644 * There are three sets of coordinate space:
645 * - physical (top, left, bottom, right)
646 * relative to graphics coord system
647 * - flow-relative (block-start, inline-start, block-end, inline-end)
648 * relative to block/inline flow directions
649 * - line-relative (line-over, line-left, line-under, line-right)
650 * relative to glyph orientation / inline bidi directions
651 * See CSS3 Writing Modes for more information
652 * http://www.w3.org/TR/css3-writing-modes/#abstract-box
654 * For shorthand, B represents the block-axis
655 * I represents the inline-axis
657 * The flow-relative geometric classes store coords in flow-relative space.
658 * They use a private ns{Point,Size,Rect,Margin} member to store the actual
659 * coordinate values, but reinterpret them as logical instead of physical.
660 * This allows us to easily perform calculations in logical space (provided
661 * writing modes of the operands match), by simply mapping to nsPoint (etc)
664 * Physical-coordinate accessors/setters are responsible to translate these
665 * internal logical values as necessary.
667 * In DEBUG builds, the logical types store their WritingMode and check
668 * that the same WritingMode is passed whenever callers ask them to do a
669 * writing-mode-dependent operation. Non-DEBUG builds do NOT check this,
670 * to avoid the overhead of storing WritingMode fields.
672 * Open question: do we need a different set optimized for line-relative
673 * math, for use in nsLineLayout and the like? Or is multiplying values
674 * by FlowRelativeToLineRelativeFactor() enough?
678 * Flow-relative point
682 explicit LogicalPoint(WritingMode aWritingMode
)
685 mWritingMode(aWritingMode
),
690 // Construct from a writing mode and individual coordinates (which MUST be
691 // values in that writing mode, NOT physical coordinates!)
692 LogicalPoint(WritingMode aWritingMode
, nscoord aI
, nscoord aB
)
695 mWritingMode(aWritingMode
),
700 // Construct from a writing mode and a physical point, within a given
701 // containing rectangle's size (defining the conversion between LTR
702 // and RTL coordinates, and between TTB and BTT coordinates).
703 LogicalPoint(WritingMode aWritingMode
, const nsPoint
& aPoint
,
704 const nsSize
& aContainerSize
)
706 : mWritingMode(aWritingMode
)
709 if (aWritingMode
.IsVertical()) {
710 I() = aWritingMode
.IsInlineReversed() ? aContainerSize
.height
- aPoint
.y
712 B() = aWritingMode
.IsVerticalLR() ? aPoint
.x
713 : aContainerSize
.width
- aPoint
.x
;
715 I() = aWritingMode
.IsInlineReversed() ? aContainerSize
.width
- aPoint
.x
722 * Read-only (const) access to the logical coordinates.
724 nscoord
I(WritingMode aWritingMode
) const // inline-axis
726 CHECK_WRITING_MODE(aWritingMode
);
729 nscoord
B(WritingMode aWritingMode
) const // block-axis
731 CHECK_WRITING_MODE(aWritingMode
);
734 nscoord
Pos(LogicalAxis aAxis
, WritingMode aWM
) const {
735 return aAxis
== eLogicalAxisInline
? I(aWM
) : B(aWM
);
737 nscoord
LineRelative(WritingMode aWritingMode
,
738 const nsSize
& aContainerSize
) const // line-axis
740 CHECK_WRITING_MODE(aWritingMode
);
741 if (aWritingMode
.IsBidiLTR()) {
744 return (aWritingMode
.IsVertical() ? aContainerSize
.height
745 : aContainerSize
.width
) -
750 * These non-const accessors return a reference (lvalue) that can be
751 * assigned to by callers.
753 nscoord
& I(WritingMode aWritingMode
) // inline-axis
755 CHECK_WRITING_MODE(aWritingMode
);
758 nscoord
& B(WritingMode aWritingMode
) // block-axis
760 CHECK_WRITING_MODE(aWritingMode
);
763 nscoord
& Pos(LogicalAxis aAxis
, WritingMode aWM
) {
764 return aAxis
== eLogicalAxisInline
? I(aWM
) : B(aWM
);
768 * Return a physical point corresponding to our logical coordinates,
769 * converted according to our writing mode.
771 nsPoint
GetPhysicalPoint(WritingMode aWritingMode
,
772 const nsSize
& aContainerSize
) const {
773 CHECK_WRITING_MODE(aWritingMode
);
774 if (aWritingMode
.IsVertical()) {
776 aWritingMode
.IsVerticalLR() ? B() : aContainerSize
.width
- B(),
777 aWritingMode
.IsInlineReversed() ? aContainerSize
.height
- I() : I());
780 aWritingMode
.IsInlineReversed() ? aContainerSize
.width
- I() : I(),
786 * Return the equivalent point in a different writing mode.
788 LogicalPoint
ConvertTo(WritingMode aToMode
, WritingMode aFromMode
,
789 const nsSize
& aContainerSize
) const {
790 CHECK_WRITING_MODE(aFromMode
);
791 return aToMode
== aFromMode
793 : LogicalPoint(aToMode
,
794 GetPhysicalPoint(aFromMode
, aContainerSize
),
798 bool operator==(const LogicalPoint
& aOther
) const {
799 CHECK_WRITING_MODE(aOther
.GetWritingMode());
800 return mPoint
== aOther
.mPoint
;
803 bool operator!=(const LogicalPoint
& aOther
) const {
804 CHECK_WRITING_MODE(aOther
.GetWritingMode());
805 return mPoint
!= aOther
.mPoint
;
808 LogicalPoint
operator+(const LogicalPoint
& aOther
) const {
809 CHECK_WRITING_MODE(aOther
.GetWritingMode());
810 // In non-debug builds, LogicalPoint does not store the WritingMode,
811 // so the first parameter here (which will always be eUnknownWritingMode)
813 return LogicalPoint(GetWritingMode(), mPoint
.x
+ aOther
.mPoint
.x
,
814 mPoint
.y
+ aOther
.mPoint
.y
);
817 LogicalPoint
& operator+=(const LogicalPoint
& aOther
) {
818 CHECK_WRITING_MODE(aOther
.GetWritingMode());
824 LogicalPoint
operator-(const LogicalPoint
& aOther
) const {
825 CHECK_WRITING_MODE(aOther
.GetWritingMode());
826 // In non-debug builds, LogicalPoint does not store the WritingMode,
827 // so the first parameter here (which will always be eUnknownWritingMode)
829 return LogicalPoint(GetWritingMode(), mPoint
.x
- aOther
.mPoint
.x
,
830 mPoint
.y
- aOther
.mPoint
.y
);
833 LogicalPoint
& operator-=(const LogicalPoint
& aOther
) {
834 CHECK_WRITING_MODE(aOther
.GetWritingMode());
840 friend std::ostream
& operator<<(std::ostream
& aStream
,
841 const LogicalPoint
& aPoint
) {
842 return aStream
<< aPoint
.mPoint
;
846 friend class LogicalRect
;
849 * NOTE that in non-DEBUG builds, GetWritingMode() always returns
850 * eUnknownWritingMode, as the current mode is not stored in the logical-
851 * geometry classes. Therefore, this method is private; it is used ONLY
852 * by the DEBUG-mode checking macros in this class and its friends;
853 * other code is not allowed to ask a logical point for its writing mode,
854 * as this info will simply not be available in non-DEBUG builds.
856 * Also, in non-DEBUG builds, CHECK_WRITING_MODE does nothing, and the
857 * WritingMode parameter to logical methods will generally be optimized
861 WritingMode
GetWritingMode() const { return mWritingMode
; }
863 WritingMode
GetWritingMode() const { return WritingMode::Unknown(); }
866 // We don't allow construction of a LogicalPoint with no writing mode.
867 LogicalPoint() = delete;
869 // Accessors that don't take or check a WritingMode value.
870 // These are for internal use only; they are called by methods that have
871 // themselves already checked the WritingMode passed by the caller.
872 nscoord
I() const // inline-axis
876 nscoord
B() const // block-axis
881 nscoord
& I() // inline-axis
885 nscoord
& B() // block-axis
891 WritingMode mWritingMode
;
894 // We use an nsPoint to hold the coordinates, but reinterpret its .x and .y
895 // fields as the inline and block directions. Hence, this is not exposed
896 // directly, but only through accessors that will map them according to the
906 explicit LogicalSize(WritingMode aWritingMode
)
909 mWritingMode(aWritingMode
),
914 LogicalSize(WritingMode aWritingMode
, nscoord aISize
, nscoord aBSize
)
917 mWritingMode(aWritingMode
),
919 mSize(aISize
, aBSize
) {
922 LogicalSize(WritingMode aWritingMode
, const nsSize
& aPhysicalSize
)
924 : mWritingMode(aWritingMode
)
927 if (aWritingMode
.IsVertical()) {
928 ISize() = aPhysicalSize
.height
;
929 BSize() = aPhysicalSize
.width
;
931 ISize() = aPhysicalSize
.width
;
932 BSize() = aPhysicalSize
.height
;
936 void SizeTo(WritingMode aWritingMode
, nscoord aISize
, nscoord aBSize
) {
937 CHECK_WRITING_MODE(aWritingMode
);
938 mSize
.SizeTo(aISize
, aBSize
);
942 * Dimensions in logical and physical terms
944 nscoord
ISize(WritingMode aWritingMode
) const // inline-size
946 CHECK_WRITING_MODE(aWritingMode
);
949 nscoord
BSize(WritingMode aWritingMode
) const // block-size
951 CHECK_WRITING_MODE(aWritingMode
);
954 nscoord
Size(LogicalAxis aAxis
, WritingMode aWM
) const {
955 return aAxis
== eLogicalAxisInline
? ISize(aWM
) : BSize(aWM
);
958 nscoord
Width(WritingMode aWritingMode
) const {
959 CHECK_WRITING_MODE(aWritingMode
);
960 return aWritingMode
.IsVertical() ? BSize() : ISize();
962 nscoord
Height(WritingMode aWritingMode
) const {
963 CHECK_WRITING_MODE(aWritingMode
);
964 return aWritingMode
.IsVertical() ? ISize() : BSize();
968 * Writable references to the logical dimensions
970 nscoord
& ISize(WritingMode aWritingMode
) // inline-size
972 CHECK_WRITING_MODE(aWritingMode
);
975 nscoord
& BSize(WritingMode aWritingMode
) // block-size
977 CHECK_WRITING_MODE(aWritingMode
);
980 nscoord
& Size(LogicalAxis aAxis
, WritingMode aWM
) {
981 return aAxis
== eLogicalAxisInline
? ISize(aWM
) : BSize(aWM
);
985 * Return an nsSize containing our physical dimensions
987 nsSize
GetPhysicalSize(WritingMode aWritingMode
) const {
988 CHECK_WRITING_MODE(aWritingMode
);
989 return aWritingMode
.IsVertical() ? nsSize(BSize(), ISize())
990 : nsSize(ISize(), BSize());
994 * Return a LogicalSize representing this size in a different writing mode
996 LogicalSize
ConvertTo(WritingMode aToMode
, WritingMode aFromMode
) const {
998 // In DEBUG builds make sure to return a LogicalSize with the
999 // expected writing mode
1000 CHECK_WRITING_MODE(aFromMode
);
1001 return aToMode
== aFromMode
1003 : LogicalSize(aToMode
, GetPhysicalSize(aFromMode
));
1005 // optimization for non-DEBUG builds where LogicalSize doesn't store
1007 return (aToMode
== aFromMode
|| !aToMode
.IsOrthogonalTo(aFromMode
))
1009 : LogicalSize(aToMode
, BSize(), ISize());
1014 * Test if a size is (0, 0).
1016 bool IsAllZero() const { return ISize() == 0 && BSize() == 0; }
1019 * Various binary operators on LogicalSize. These are valid ONLY for operands
1020 * that share the same writing mode.
1022 bool operator==(const LogicalSize
& aOther
) const {
1023 CHECK_WRITING_MODE(aOther
.GetWritingMode());
1024 return mSize
== aOther
.mSize
;
1027 bool operator!=(const LogicalSize
& aOther
) const {
1028 CHECK_WRITING_MODE(aOther
.GetWritingMode());
1029 return mSize
!= aOther
.mSize
;
1032 LogicalSize
operator+(const LogicalSize
& aOther
) const {
1033 CHECK_WRITING_MODE(aOther
.GetWritingMode());
1034 return LogicalSize(GetWritingMode(), ISize() + aOther
.ISize(),
1035 BSize() + aOther
.BSize());
1037 LogicalSize
& operator+=(const LogicalSize
& aOther
) {
1038 CHECK_WRITING_MODE(aOther
.GetWritingMode());
1039 ISize() += aOther
.ISize();
1040 BSize() += aOther
.BSize();
1044 LogicalSize
operator-(const LogicalSize
& aOther
) const {
1045 CHECK_WRITING_MODE(aOther
.GetWritingMode());
1046 return LogicalSize(GetWritingMode(), ISize() - aOther
.ISize(),
1047 BSize() - aOther
.BSize());
1049 LogicalSize
& operator-=(const LogicalSize
& aOther
) {
1050 CHECK_WRITING_MODE(aOther
.GetWritingMode());
1051 ISize() -= aOther
.ISize();
1052 BSize() -= aOther
.BSize();
1056 friend std::ostream
& operator<<(std::ostream
& aStream
,
1057 const LogicalSize
& aSize
) {
1058 return aStream
<< aSize
.mSize
;
1062 friend class LogicalRect
;
1064 LogicalSize() = delete;
1067 WritingMode
GetWritingMode() const { return mWritingMode
; }
1069 WritingMode
GetWritingMode() const { return WritingMode::Unknown(); }
1072 nscoord
ISize() const // inline-size
1076 nscoord
BSize() const // block-size
1078 return mSize
.height
;
1081 nscoord
& ISize() // inline-size
1085 nscoord
& BSize() // block-size
1087 return mSize
.height
;
1091 WritingMode mWritingMode
;
1097 * LogicalSides represents a set of logical sides.
1099 struct LogicalSides final
{
1100 explicit LogicalSides(WritingMode aWritingMode
)
1103 mWritingMode(aWritingMode
),
1107 LogicalSides(WritingMode aWritingMode
, LogicalSideBits aSideBits
)
1110 mWritingMode(aWritingMode
),
1113 MOZ_ASSERT((aSideBits
& ~eLogicalSideBitsAll
) == 0, "illegal side bits");
1115 bool IsEmpty() const { return mBits
== 0; }
1116 bool BStart() const { return mBits
& eLogicalSideBitsBStart
; }
1117 bool BEnd() const { return mBits
& eLogicalSideBitsBEnd
; }
1118 bool IStart() const { return mBits
& eLogicalSideBitsIStart
; }
1119 bool IEnd() const { return mBits
& eLogicalSideBitsIEnd
; }
1120 bool Contains(LogicalSideBits aSideBits
) const {
1121 MOZ_ASSERT((aSideBits
& ~eLogicalSideBitsAll
) == 0, "illegal side bits");
1122 return (mBits
& aSideBits
) == aSideBits
;
1124 LogicalSides
operator|(LogicalSides aOther
) const {
1125 CHECK_WRITING_MODE(aOther
.GetWritingMode());
1126 return *this | LogicalSideBits(aOther
.mBits
);
1128 LogicalSides
operator|(LogicalSideBits aSideBits
) const {
1129 return LogicalSides(GetWritingMode(), LogicalSideBits(mBits
| aSideBits
));
1131 LogicalSides
& operator|=(LogicalSides aOther
) {
1132 CHECK_WRITING_MODE(aOther
.GetWritingMode());
1133 return *this |= LogicalSideBits(aOther
.mBits
);
1135 LogicalSides
& operator|=(LogicalSideBits aSideBits
) {
1139 bool operator==(LogicalSides aOther
) const {
1140 CHECK_WRITING_MODE(aOther
.GetWritingMode());
1141 return mBits
== aOther
.mBits
;
1143 bool operator!=(LogicalSides aOther
) const {
1144 CHECK_WRITING_MODE(aOther
.GetWritingMode());
1145 return !(*this == aOther
);
1149 WritingMode
GetWritingMode() const { return mWritingMode
; }
1151 WritingMode
GetWritingMode() const { return WritingMode::Unknown(); }
1156 WritingMode mWritingMode
;
1162 * Flow-relative margin
1164 class LogicalMargin
{
1166 explicit LogicalMargin(WritingMode aWritingMode
)
1169 mWritingMode(aWritingMode
),
1171 mMargin(0, 0, 0, 0) {
1174 LogicalMargin(WritingMode aWritingMode
, nscoord aBStart
, nscoord aIEnd
,
1175 nscoord aBEnd
, nscoord aIStart
)
1178 mWritingMode(aWritingMode
),
1180 mMargin(aBStart
, aIEnd
, aBEnd
, aIStart
) {
1183 LogicalMargin(WritingMode aWritingMode
, const nsMargin
& aPhysicalMargin
)
1185 : mWritingMode(aWritingMode
)
1188 if (aWritingMode
.IsVertical()) {
1189 if (aWritingMode
.IsVerticalLR()) {
1190 mMargin
.top
= aPhysicalMargin
.left
;
1191 mMargin
.bottom
= aPhysicalMargin
.right
;
1193 mMargin
.top
= aPhysicalMargin
.right
;
1194 mMargin
.bottom
= aPhysicalMargin
.left
;
1196 if (aWritingMode
.IsInlineReversed()) {
1197 mMargin
.left
= aPhysicalMargin
.bottom
;
1198 mMargin
.right
= aPhysicalMargin
.top
;
1200 mMargin
.left
= aPhysicalMargin
.top
;
1201 mMargin
.right
= aPhysicalMargin
.bottom
;
1204 mMargin
.top
= aPhysicalMargin
.top
;
1205 mMargin
.bottom
= aPhysicalMargin
.bottom
;
1206 if (aWritingMode
.IsInlineReversed()) {
1207 mMargin
.left
= aPhysicalMargin
.right
;
1208 mMargin
.right
= aPhysicalMargin
.left
;
1210 mMargin
.left
= aPhysicalMargin
.left
;
1211 mMargin
.right
= aPhysicalMargin
.right
;
1216 nscoord
IStart(WritingMode aWritingMode
) const // inline-start margin
1218 CHECK_WRITING_MODE(aWritingMode
);
1219 return mMargin
.left
;
1221 nscoord
IEnd(WritingMode aWritingMode
) const // inline-end margin
1223 CHECK_WRITING_MODE(aWritingMode
);
1224 return mMargin
.right
;
1226 nscoord
BStart(WritingMode aWritingMode
) const // block-start margin
1228 CHECK_WRITING_MODE(aWritingMode
);
1231 nscoord
BEnd(WritingMode aWritingMode
) const // block-end margin
1233 CHECK_WRITING_MODE(aWritingMode
);
1234 return mMargin
.bottom
;
1236 nscoord
Start(LogicalAxis aAxis
, WritingMode aWM
) const {
1237 return aAxis
== eLogicalAxisInline
? IStart(aWM
) : BStart(aWM
);
1239 nscoord
End(LogicalAxis aAxis
, WritingMode aWM
) const {
1240 return aAxis
== eLogicalAxisInline
? IEnd(aWM
) : BEnd(aWM
);
1243 nscoord
& IStart(WritingMode aWritingMode
) // inline-start margin
1245 CHECK_WRITING_MODE(aWritingMode
);
1246 return mMargin
.left
;
1248 nscoord
& IEnd(WritingMode aWritingMode
) // inline-end margin
1250 CHECK_WRITING_MODE(aWritingMode
);
1251 return mMargin
.right
;
1253 nscoord
& BStart(WritingMode aWritingMode
) // block-start margin
1255 CHECK_WRITING_MODE(aWritingMode
);
1258 nscoord
& BEnd(WritingMode aWritingMode
) // block-end margin
1260 CHECK_WRITING_MODE(aWritingMode
);
1261 return mMargin
.bottom
;
1263 nscoord
& Start(LogicalAxis aAxis
, WritingMode aWM
) {
1264 return aAxis
== eLogicalAxisInline
? IStart(aWM
) : BStart(aWM
);
1266 nscoord
& End(LogicalAxis aAxis
, WritingMode aWM
) {
1267 return aAxis
== eLogicalAxisInline
? IEnd(aWM
) : BEnd(aWM
);
1270 nscoord
IStartEnd(WritingMode aWritingMode
) const // inline margins
1272 CHECK_WRITING_MODE(aWritingMode
);
1273 return mMargin
.LeftRight();
1275 nscoord
BStartEnd(WritingMode aWritingMode
) const // block margins
1277 CHECK_WRITING_MODE(aWritingMode
);
1278 return mMargin
.TopBottom();
1280 nscoord
StartEnd(LogicalAxis aAxis
, WritingMode aWM
) const {
1281 return aAxis
== eLogicalAxisInline
? IStartEnd(aWM
) : BStartEnd(aWM
);
1284 nscoord
Side(LogicalSide aSide
, WritingMode aWM
) const {
1286 case eLogicalSideBStart
:
1288 case eLogicalSideBEnd
:
1290 case eLogicalSideIStart
:
1292 case eLogicalSideIEnd
:
1296 MOZ_ASSERT_UNREACHABLE("We should handle all sides!");
1299 nscoord
& Side(LogicalSide aSide
, WritingMode aWM
) {
1301 case eLogicalSideBStart
:
1303 case eLogicalSideBEnd
:
1305 case eLogicalSideIStart
:
1307 case eLogicalSideIEnd
:
1311 MOZ_ASSERT_UNREACHABLE("We should handle all sides!");
1316 * Return margin values for line-relative sides, as defined in
1317 * http://www.w3.org/TR/css-writing-modes-3/#line-directions:
1320 * Nominally the side from which LTR text would start.
1322 * Nominally the side from which RTL text would start. (Opposite of
1325 nscoord
LineLeft(WritingMode aWritingMode
) const {
1326 // We don't need to CHECK_WRITING_MODE here because the IStart or IEnd
1327 // accessor that we call will do it.
1328 return aWritingMode
.IsBidiLTR() ? IStart(aWritingMode
) : IEnd(aWritingMode
);
1330 nscoord
LineRight(WritingMode aWritingMode
) const {
1331 return aWritingMode
.IsBidiLTR() ? IEnd(aWritingMode
) : IStart(aWritingMode
);
1335 * Return a LogicalSize representing the total size of the inline-
1336 * and block-dimension margins.
1338 LogicalSize
Size(WritingMode aWritingMode
) const {
1339 CHECK_WRITING_MODE(aWritingMode
);
1340 return LogicalSize(aWritingMode
, IStartEnd(), BStartEnd());
1344 * Return a LogicalPoint representing an offset to the start-sides, i.e.
1345 * inline-start and block-start.
1347 LogicalPoint
StartOffset(WritingMode aWritingMode
) const {
1348 CHECK_WRITING_MODE(aWritingMode
);
1349 return LogicalPoint(aWritingMode
, IStart(), BStart());
1353 * Accessors for physical margins, using our writing mode to convert from
1356 nscoord
Top(WritingMode aWritingMode
) const {
1357 CHECK_WRITING_MODE(aWritingMode
);
1358 return aWritingMode
.IsVertical()
1359 ? (aWritingMode
.IsInlineReversed() ? IEnd() : IStart())
1363 nscoord
Bottom(WritingMode aWritingMode
) const {
1364 CHECK_WRITING_MODE(aWritingMode
);
1365 return aWritingMode
.IsVertical()
1366 ? (aWritingMode
.IsInlineReversed() ? IStart() : IEnd())
1370 nscoord
Left(WritingMode aWritingMode
) const {
1371 CHECK_WRITING_MODE(aWritingMode
);
1372 return aWritingMode
.IsVertical()
1373 ? (aWritingMode
.IsVerticalLR() ? BStart() : BEnd())
1374 : (aWritingMode
.IsInlineReversed() ? IEnd() : IStart());
1377 nscoord
Right(WritingMode aWritingMode
) const {
1378 CHECK_WRITING_MODE(aWritingMode
);
1379 return aWritingMode
.IsVertical()
1380 ? (aWritingMode
.IsVerticalLR() ? BEnd() : BStart())
1381 : (aWritingMode
.IsInlineReversed() ? IStart() : IEnd());
1384 nscoord
LeftRight(WritingMode aWritingMode
) const {
1385 CHECK_WRITING_MODE(aWritingMode
);
1386 return aWritingMode
.IsVertical() ? BStartEnd() : IStartEnd();
1389 nscoord
TopBottom(WritingMode aWritingMode
) const {
1390 CHECK_WRITING_MODE(aWritingMode
);
1391 return aWritingMode
.IsVertical() ? IStartEnd() : BStartEnd();
1394 void SizeTo(WritingMode aWritingMode
, nscoord aBStart
, nscoord aIEnd
,
1395 nscoord aBEnd
, nscoord aIStart
) {
1396 CHECK_WRITING_MODE(aWritingMode
);
1397 mMargin
.SizeTo(aBStart
, aIEnd
, aBEnd
, aIStart
);
1401 * Return an nsMargin containing our physical coordinates
1403 nsMargin
GetPhysicalMargin(WritingMode aWritingMode
) const {
1404 CHECK_WRITING_MODE(aWritingMode
);
1405 return aWritingMode
.IsVertical()
1406 ? (aWritingMode
.IsVerticalLR()
1407 ? (aWritingMode
.IsInlineReversed()
1408 ? nsMargin(IEnd(), BEnd(), IStart(), BStart())
1409 : nsMargin(IStart(), BEnd(), IEnd(), BStart()))
1410 : (aWritingMode
.IsInlineReversed()
1411 ? nsMargin(IEnd(), BStart(), IStart(), BEnd())
1412 : nsMargin(IStart(), BStart(), IEnd(), BEnd())))
1413 : (aWritingMode
.IsInlineReversed()
1414 ? nsMargin(BStart(), IStart(), BEnd(), IEnd())
1415 : nsMargin(BStart(), IEnd(), BEnd(), IStart()));
1419 * Return a LogicalMargin representing this margin in a different
1422 LogicalMargin
ConvertTo(WritingMode aToMode
, WritingMode aFromMode
) const {
1423 CHECK_WRITING_MODE(aFromMode
);
1424 return aToMode
== aFromMode
1426 : LogicalMargin(aToMode
, GetPhysicalMargin(aFromMode
));
1429 LogicalMargin
& ApplySkipSides(LogicalSides aSkipSides
) {
1430 CHECK_WRITING_MODE(aSkipSides
.GetWritingMode());
1431 if (aSkipSides
.BStart()) {
1434 if (aSkipSides
.BEnd()) {
1437 if (aSkipSides
.IStart()) {
1440 if (aSkipSides
.IEnd()) {
1446 bool IsAllZero() const {
1447 return (mMargin
.left
== 0 && mMargin
.top
== 0 && mMargin
.right
== 0 &&
1448 mMargin
.bottom
== 0);
1451 bool operator==(const LogicalMargin
& aMargin
) const {
1452 CHECK_WRITING_MODE(aMargin
.GetWritingMode());
1453 return mMargin
== aMargin
.mMargin
;
1456 bool operator!=(const LogicalMargin
& aMargin
) const {
1457 CHECK_WRITING_MODE(aMargin
.GetWritingMode());
1458 return mMargin
!= aMargin
.mMargin
;
1461 LogicalMargin
operator+(const LogicalMargin
& aMargin
) const {
1462 CHECK_WRITING_MODE(aMargin
.GetWritingMode());
1463 return LogicalMargin(GetWritingMode(), BStart() + aMargin
.BStart(),
1464 IEnd() + aMargin
.IEnd(), BEnd() + aMargin
.BEnd(),
1465 IStart() + aMargin
.IStart());
1468 LogicalMargin
operator+=(const LogicalMargin
& aMargin
) {
1469 CHECK_WRITING_MODE(aMargin
.GetWritingMode());
1470 mMargin
+= aMargin
.mMargin
;
1474 LogicalMargin
operator-(const LogicalMargin
& aMargin
) const {
1475 CHECK_WRITING_MODE(aMargin
.GetWritingMode());
1476 return LogicalMargin(GetWritingMode(), BStart() - aMargin
.BStart(),
1477 IEnd() - aMargin
.IEnd(), BEnd() - aMargin
.BEnd(),
1478 IStart() - aMargin
.IStart());
1481 friend std::ostream
& operator<<(std::ostream
& aStream
,
1482 const LogicalMargin
& aMargin
) {
1483 return aStream
<< aMargin
.mMargin
;
1487 friend class LogicalRect
;
1489 LogicalMargin() = delete;
1492 WritingMode
GetWritingMode() const { return mWritingMode
; }
1494 WritingMode
GetWritingMode() const { return WritingMode::Unknown(); }
1497 nscoord
IStart() const // inline-start margin
1499 return mMargin
.left
;
1501 nscoord
IEnd() const // inline-end margin
1503 return mMargin
.right
;
1505 nscoord
BStart() const // block-start margin
1509 nscoord
BEnd() const // block-end margin
1511 return mMargin
.bottom
;
1514 nscoord
& IStart() // inline-start margin
1516 return mMargin
.left
;
1518 nscoord
& IEnd() // inline-end margin
1520 return mMargin
.right
;
1522 nscoord
& BStart() // block-start margin
1526 nscoord
& BEnd() // block-end margin
1528 return mMargin
.bottom
;
1531 nscoord
IStartEnd() const // inline margins
1533 return mMargin
.LeftRight();
1535 nscoord
BStartEnd() const // block margins
1537 return mMargin
.TopBottom();
1541 WritingMode mWritingMode
;
1547 * Flow-relative rectangle
1551 explicit LogicalRect(WritingMode aWritingMode
)
1554 mWritingMode(aWritingMode
),
1562 LogicalRect(WritingMode aWritingMode
, nscoord aIStart
, nscoord aBStart
,
1563 nscoord aISize
, nscoord aBSize
)
1566 mWritingMode(aWritingMode
),
1574 LogicalRect(WritingMode aWritingMode
, const LogicalPoint
& aOrigin
,
1575 const LogicalSize
& aSize
)
1578 mWritingMode(aWritingMode
),
1580 mIStart(aOrigin
.mPoint
.x
),
1581 mBStart(aOrigin
.mPoint
.y
),
1582 mISize(aSize
.mSize
.width
),
1583 mBSize(aSize
.mSize
.height
) {
1584 CHECK_WRITING_MODE(aOrigin
.GetWritingMode());
1585 CHECK_WRITING_MODE(aSize
.GetWritingMode());
1588 LogicalRect(WritingMode aWritingMode
, const nsRect
& aRect
,
1589 const nsSize
& aContainerSize
)
1591 : mWritingMode(aWritingMode
)
1594 if (aWritingMode
.IsVertical()) {
1595 mBStart
= aWritingMode
.IsVerticalLR()
1597 : aContainerSize
.width
- aRect
.XMost();
1598 mIStart
= aWritingMode
.IsInlineReversed()
1599 ? aContainerSize
.height
- aRect
.YMost()
1601 mBSize
= aRect
.Width();
1602 mISize
= aRect
.Height();
1604 mIStart
= aWritingMode
.IsInlineReversed()
1605 ? aContainerSize
.width
- aRect
.XMost()
1607 mBStart
= aRect
.Y();
1608 mISize
= aRect
.Width();
1609 mBSize
= aRect
.Height();
1614 * Inline- and block-dimension geometry.
1616 nscoord
IStart(WritingMode aWritingMode
) const // inline-start edge
1618 CHECK_WRITING_MODE(aWritingMode
);
1621 nscoord
IEnd(WritingMode aWritingMode
) const // inline-end edge
1623 CHECK_WRITING_MODE(aWritingMode
);
1624 return mIStart
+ mISize
;
1626 nscoord
ISize(WritingMode aWritingMode
) const // inline-size
1628 CHECK_WRITING_MODE(aWritingMode
);
1632 nscoord
BStart(WritingMode aWritingMode
) const // block-start edge
1634 CHECK_WRITING_MODE(aWritingMode
);
1637 nscoord
BEnd(WritingMode aWritingMode
) const // block-end edge
1639 CHECK_WRITING_MODE(aWritingMode
);
1640 return mBStart
+ mBSize
;
1642 nscoord
BSize(WritingMode aWritingMode
) const // block-size
1644 CHECK_WRITING_MODE(aWritingMode
);
1648 nscoord
Start(LogicalAxis aAxis
, WritingMode aWM
) const {
1649 return aAxis
== eLogicalAxisInline
? IStart(aWM
) : BStart(aWM
);
1651 nscoord
End(LogicalAxis aAxis
, WritingMode aWM
) const {
1652 return aAxis
== eLogicalAxisInline
? IEnd(aWM
) : BEnd(aWM
);
1654 nscoord
Size(LogicalAxis aAxis
, WritingMode aWM
) const {
1655 return aAxis
== eLogicalAxisInline
? ISize(aWM
) : BSize(aWM
);
1659 * Writable (reference) accessors are only available for the basic logical
1660 * fields (Start and Size), not derivatives like End.
1662 nscoord
& IStart(WritingMode aWritingMode
) // inline-start edge
1664 CHECK_WRITING_MODE(aWritingMode
);
1667 nscoord
& ISize(WritingMode aWritingMode
) // inline-size
1669 CHECK_WRITING_MODE(aWritingMode
);
1672 nscoord
& BStart(WritingMode aWritingMode
) // block-start edge
1674 CHECK_WRITING_MODE(aWritingMode
);
1677 nscoord
& BSize(WritingMode aWritingMode
) // block-size
1679 CHECK_WRITING_MODE(aWritingMode
);
1682 nscoord
& Start(LogicalAxis aAxis
, WritingMode aWM
) {
1683 return aAxis
== eLogicalAxisInline
? IStart(aWM
) : BStart(aWM
);
1685 nscoord
& Size(LogicalAxis aAxis
, WritingMode aWM
) {
1686 return aAxis
== eLogicalAxisInline
? ISize(aWM
) : BSize(aWM
);
1690 * Accessors for line-relative coordinates
1692 nscoord
LineLeft(WritingMode aWritingMode
,
1693 const nsSize
& aContainerSize
) const {
1694 CHECK_WRITING_MODE(aWritingMode
);
1695 if (aWritingMode
.IsBidiLTR()) {
1698 nscoord containerISize
= aWritingMode
.IsVertical() ? aContainerSize
.height
1699 : aContainerSize
.width
;
1700 return containerISize
- IEnd();
1702 nscoord
LineRight(WritingMode aWritingMode
,
1703 const nsSize
& aContainerSize
) const {
1704 CHECK_WRITING_MODE(aWritingMode
);
1705 if (aWritingMode
.IsBidiLTR()) {
1708 nscoord containerISize
= aWritingMode
.IsVertical() ? aContainerSize
.height
1709 : aContainerSize
.width
;
1710 return containerISize
- IStart();
1714 * Physical coordinates of the rect.
1716 nscoord
X(WritingMode aWritingMode
, nscoord aContainerWidth
) const {
1717 CHECK_WRITING_MODE(aWritingMode
);
1718 if (aWritingMode
.IsVertical()) {
1719 return aWritingMode
.IsVerticalLR() ? mBStart
: aContainerWidth
- BEnd();
1721 return aWritingMode
.IsInlineReversed() ? aContainerWidth
- IEnd() : mIStart
;
1724 nscoord
Y(WritingMode aWritingMode
, nscoord aContainerHeight
) const {
1725 CHECK_WRITING_MODE(aWritingMode
);
1726 if (aWritingMode
.IsVertical()) {
1727 return aWritingMode
.IsInlineReversed() ? aContainerHeight
- IEnd()
1733 nscoord
Width(WritingMode aWritingMode
) const {
1734 CHECK_WRITING_MODE(aWritingMode
);
1735 return aWritingMode
.IsVertical() ? mBSize
: mISize
;
1738 nscoord
Height(WritingMode aWritingMode
) const {
1739 CHECK_WRITING_MODE(aWritingMode
);
1740 return aWritingMode
.IsVertical() ? mISize
: mBSize
;
1743 nscoord
XMost(WritingMode aWritingMode
, nscoord aContainerWidth
) const {
1744 CHECK_WRITING_MODE(aWritingMode
);
1745 if (aWritingMode
.IsVertical()) {
1746 return aWritingMode
.IsVerticalLR() ? BEnd() : aContainerWidth
- mBStart
;
1748 return aWritingMode
.IsInlineReversed() ? aContainerWidth
- mIStart
: IEnd();
1751 nscoord
YMost(WritingMode aWritingMode
, nscoord aContainerHeight
) const {
1752 CHECK_WRITING_MODE(aWritingMode
);
1753 if (aWritingMode
.IsVertical()) {
1754 return aWritingMode
.IsInlineReversed() ? aContainerHeight
- mIStart
1760 bool IsEmpty() const { return mISize
<= 0 || mBSize
<= 0; }
1762 bool IsAllZero() const {
1763 return (mIStart
== 0 && mBStart
== 0 && mISize
== 0 && mBSize
== 0);
1766 bool IsZeroSize() const { return (mISize
== 0 && mBSize
== 0); }
1768 void SetEmpty() { mISize
= mBSize
= 0; }
1770 bool IsEqualEdges(const LogicalRect aOther
) const {
1771 CHECK_WRITING_MODE(aOther
.GetWritingMode());
1772 bool result
= mIStart
== aOther
.mIStart
&& mBStart
== aOther
.mBStart
&&
1773 mISize
== aOther
.mISize
&& mBSize
== aOther
.mBSize
;
1775 // We want the same result as nsRect, so assert we get it.
1776 MOZ_ASSERT(result
==
1777 nsRect(mIStart
, mBStart
, mISize
, mBSize
)
1778 .IsEqualEdges(nsRect(aOther
.mIStart
, aOther
.mBStart
,
1779 aOther
.mISize
, aOther
.mBSize
)));
1783 LogicalPoint
Origin(WritingMode aWritingMode
) const {
1784 CHECK_WRITING_MODE(aWritingMode
);
1785 return LogicalPoint(aWritingMode
, IStart(), BStart());
1787 void SetOrigin(WritingMode aWritingMode
, const LogicalPoint
& aPoint
) {
1788 IStart(aWritingMode
) = aPoint
.I(aWritingMode
);
1789 BStart(aWritingMode
) = aPoint
.B(aWritingMode
);
1792 LogicalSize
Size(WritingMode aWritingMode
) const {
1793 CHECK_WRITING_MODE(aWritingMode
);
1794 return LogicalSize(aWritingMode
, ISize(), BSize());
1797 LogicalRect
operator+(const LogicalPoint
& aPoint
) const {
1798 CHECK_WRITING_MODE(aPoint
.GetWritingMode());
1799 return LogicalRect(GetWritingMode(), IStart() + aPoint
.I(),
1800 BStart() + aPoint
.B(), ISize(), BSize());
1803 LogicalRect
& operator+=(const LogicalPoint
& aPoint
) {
1804 CHECK_WRITING_MODE(aPoint
.GetWritingMode());
1805 mIStart
+= aPoint
.mPoint
.x
;
1806 mBStart
+= aPoint
.mPoint
.y
;
1810 LogicalRect
operator-(const LogicalPoint
& aPoint
) const {
1811 CHECK_WRITING_MODE(aPoint
.GetWritingMode());
1812 return LogicalRect(GetWritingMode(), IStart() - aPoint
.I(),
1813 BStart() - aPoint
.B(), ISize(), BSize());
1816 LogicalRect
& operator-=(const LogicalPoint
& aPoint
) {
1817 CHECK_WRITING_MODE(aPoint
.GetWritingMode());
1818 mIStart
-= aPoint
.mPoint
.x
;
1819 mBStart
-= aPoint
.mPoint
.y
;
1823 void MoveBy(WritingMode aWritingMode
, const LogicalPoint
& aDelta
) {
1824 CHECK_WRITING_MODE(aWritingMode
);
1825 CHECK_WRITING_MODE(aDelta
.GetWritingMode());
1826 IStart() += aDelta
.I();
1827 BStart() += aDelta
.B();
1830 void Inflate(nscoord aD
) {
1832 // Compute using nsRect and assert the results match
1833 nsRect
rectDebug(mIStart
, mBStart
, mISize
, mBSize
);
1834 rectDebug
.Inflate(aD
);
1841 rectDebug
.IsEqualEdges(nsRect(mIStart
, mBStart
, mISize
, mBSize
)));
1843 void Inflate(nscoord aDI
, nscoord aDB
) {
1845 // Compute using nsRect and assert the results match
1846 nsRect
rectDebug(mIStart
, mBStart
, mISize
, mBSize
);
1847 rectDebug
.Inflate(aDI
, aDB
);
1854 rectDebug
.IsEqualEdges(nsRect(mIStart
, mBStart
, mISize
, mBSize
)));
1856 void Inflate(WritingMode aWritingMode
, const LogicalMargin
& aMargin
) {
1857 CHECK_WRITING_MODE(aWritingMode
);
1858 CHECK_WRITING_MODE(aMargin
.GetWritingMode());
1860 // Compute using nsRect and assert the results match
1861 nsRect
rectDebug(mIStart
, mBStart
, mISize
, mBSize
);
1862 rectDebug
.Inflate(aMargin
.mMargin
);
1864 mIStart
-= aMargin
.mMargin
.left
;
1865 mBStart
-= aMargin
.mMargin
.top
;
1866 mISize
+= aMargin
.mMargin
.LeftRight();
1867 mBSize
+= aMargin
.mMargin
.TopBottom();
1869 rectDebug
.IsEqualEdges(nsRect(mIStart
, mBStart
, mISize
, mBSize
)));
1872 void Deflate(nscoord aD
) {
1874 // Compute using nsRect and assert the results match
1875 nsRect
rectDebug(mIStart
, mBStart
, mISize
, mBSize
);
1876 rectDebug
.Deflate(aD
);
1880 mISize
= std::max(0, mISize
- 2 * aD
);
1881 mBSize
= std::max(0, mBSize
- 2 * aD
);
1883 rectDebug
.IsEqualEdges(nsRect(mIStart
, mBStart
, mISize
, mBSize
)));
1885 void Deflate(nscoord aDI
, nscoord aDB
) {
1887 // Compute using nsRect and assert the results match
1888 nsRect
rectDebug(mIStart
, mBStart
, mISize
, mBSize
);
1889 rectDebug
.Deflate(aDI
, aDB
);
1893 mISize
= std::max(0, mISize
- 2 * aDI
);
1894 mBSize
= std::max(0, mBSize
- 2 * aDB
);
1896 rectDebug
.IsEqualEdges(nsRect(mIStart
, mBStart
, mISize
, mBSize
)));
1898 void Deflate(WritingMode aWritingMode
, const LogicalMargin
& aMargin
) {
1899 CHECK_WRITING_MODE(aWritingMode
);
1900 CHECK_WRITING_MODE(aMargin
.GetWritingMode());
1902 // Compute using nsRect and assert the results match
1903 nsRect
rectDebug(mIStart
, mBStart
, mISize
, mBSize
);
1904 rectDebug
.Deflate(aMargin
.mMargin
);
1906 mIStart
+= aMargin
.mMargin
.left
;
1907 mBStart
+= aMargin
.mMargin
.top
;
1908 mISize
= std::max(0, mISize
- aMargin
.mMargin
.LeftRight());
1909 mBSize
= std::max(0, mBSize
- aMargin
.mMargin
.TopBottom());
1911 rectDebug
.IsEqualEdges(nsRect(mIStart
, mBStart
, mISize
, mBSize
)));
1915 * Return an nsRect containing our physical coordinates within the given
1918 nsRect
GetPhysicalRect(WritingMode aWritingMode
,
1919 const nsSize
& aContainerSize
) const {
1920 CHECK_WRITING_MODE(aWritingMode
);
1921 if (aWritingMode
.IsVertical()) {
1922 return nsRect(aWritingMode
.IsVerticalLR() ? BStart()
1923 : aContainerSize
.width
- BEnd(),
1924 aWritingMode
.IsInlineReversed()
1925 ? aContainerSize
.height
- IEnd()
1929 return nsRect(aWritingMode
.IsInlineReversed()
1930 ? aContainerSize
.width
- IEnd()
1932 BStart(), ISize(), BSize());
1937 * Return a LogicalRect representing this rect in a different writing mode
1939 LogicalRect
ConvertTo(WritingMode aToMode
, WritingMode aFromMode
,
1940 const nsSize
& aContainerSize
) const {
1941 CHECK_WRITING_MODE(aFromMode
);
1942 return aToMode
== aFromMode
1944 : LogicalRect(aToMode
,
1945 GetPhysicalRect(aFromMode
, aContainerSize
),
1950 * Set *this to be the rectangle containing the intersection of aRect1
1951 * and aRect2, return whether the intersection is non-empty.
1953 bool IntersectRect(const LogicalRect
& aRect1
, const LogicalRect
& aRect2
) {
1954 CHECK_WRITING_MODE(aRect1
.mWritingMode
);
1955 CHECK_WRITING_MODE(aRect2
.mWritingMode
);
1957 // Compute using nsRect and assert the results match
1959 rectDebug
.IntersectRect(
1960 nsRect(aRect1
.mIStart
, aRect1
.mBStart
, aRect1
.mISize
, aRect1
.mBSize
),
1961 nsRect(aRect2
.mIStart
, aRect2
.mBStart
, aRect2
.mISize
, aRect2
.mBSize
));
1964 nscoord iEnd
= std::min(aRect1
.IEnd(), aRect2
.IEnd());
1965 mIStart
= std::max(aRect1
.mIStart
, aRect2
.mIStart
);
1966 mISize
= iEnd
- mIStart
;
1968 nscoord bEnd
= std::min(aRect1
.BEnd(), aRect2
.BEnd());
1969 mBStart
= std::max(aRect1
.mBStart
, aRect2
.mBStart
);
1970 mBSize
= bEnd
- mBStart
;
1972 if (mISize
< 0 || mBSize
< 0) {
1978 (rectDebug
.IsEmpty() && (mISize
== 0 || mBSize
== 0)) ||
1979 rectDebug
.IsEqualEdges(nsRect(mIStart
, mBStart
, mISize
, mBSize
)));
1980 return mISize
> 0 && mBSize
> 0;
1983 friend std::ostream
& operator<<(std::ostream
& aStream
,
1984 const LogicalRect
& aRect
) {
1985 return aStream
<< '(' << aRect
.IStart() << ',' << aRect
.BStart() << ','
1986 << aRect
.ISize() << ',' << aRect
.BSize() << ')';
1990 LogicalRect() = delete;
1993 WritingMode
GetWritingMode() const { return mWritingMode
; }
1995 WritingMode
GetWritingMode() const { return WritingMode::Unknown(); }
1998 nscoord
IStart() const // inline-start edge
2002 nscoord
IEnd() const // inline-end edge
2004 return mIStart
+ mISize
;
2006 nscoord
ISize() const // inline-size
2011 nscoord
BStart() const // block-start edge
2015 nscoord
BEnd() const // block-end edge
2017 return mBStart
+ mBSize
;
2019 nscoord
BSize() const // block-size
2024 nscoord
& IStart() // inline-start edge
2028 nscoord
& ISize() // inline-size
2032 nscoord
& BStart() // block-start edge
2036 nscoord
& BSize() // block-size
2042 WritingMode mWritingMode
;
2044 // Inline- and block-geometry dimension
2045 nscoord mIStart
; // inline-start edge
2046 nscoord mBStart
; // block-start edge
2047 nscoord mISize
; // inline-size
2048 nscoord mBSize
; // block-size
2051 template <typename T
>
2052 const T
& StyleRect
<T
>::Get(WritingMode aWM
, LogicalSide aSide
) const {
2053 return Get(aWM
.PhysicalSide(aSide
));
2056 template <typename T
>
2057 const T
& StyleRect
<T
>::GetIStart(WritingMode aWM
) const {
2058 return Get(aWM
, eLogicalSideIStart
);
2061 template <typename T
>
2062 const T
& StyleRect
<T
>::GetBStart(WritingMode aWM
) const {
2063 return Get(aWM
, eLogicalSideBStart
);
2066 template <typename T
>
2067 const T
& StyleRect
<T
>::GetIEnd(WritingMode aWM
) const {
2068 return Get(aWM
, eLogicalSideIEnd
);
2071 template <typename T
>
2072 const T
& StyleRect
<T
>::GetBEnd(WritingMode aWM
) const {
2073 return Get(aWM
, eLogicalSideBEnd
);
2076 template <typename T
>
2077 T
& StyleRect
<T
>::Get(WritingMode aWM
, LogicalSide aSide
) {
2078 return Get(aWM
.PhysicalSide(aSide
));
2081 template <typename T
>
2082 T
& StyleRect
<T
>::GetIStart(WritingMode aWM
) {
2083 return Get(aWM
, eLogicalSideIStart
);
2086 template <typename T
>
2087 T
& StyleRect
<T
>::GetBStart(WritingMode aWM
) {
2088 return Get(aWM
, eLogicalSideBStart
);
2091 template <typename T
>
2092 T
& StyleRect
<T
>::GetIEnd(WritingMode aWM
) {
2093 return Get(aWM
, eLogicalSideIEnd
);
2096 template <typename T
>
2097 T
& StyleRect
<T
>::GetBEnd(WritingMode aWM
) {
2098 return Get(aWM
, eLogicalSideBEnd
);
2101 template <typename T
>
2102 const T
& StyleRect
<T
>::Start(mozilla::LogicalAxis aAxis
,
2103 mozilla::WritingMode aWM
) const {
2104 return Get(aWM
, aAxis
== mozilla::eLogicalAxisInline
2105 ? mozilla::eLogicalSideIStart
2106 : mozilla::eLogicalSideBStart
);
2109 template <typename T
>
2110 const T
& StyleRect
<T
>::End(mozilla::LogicalAxis aAxis
,
2111 mozilla::WritingMode aWM
) const {
2112 return Get(aWM
, aAxis
== mozilla::eLogicalAxisInline
2113 ? mozilla::eLogicalSideIEnd
2114 : mozilla::eLogicalSideBEnd
);
2117 inline AspectRatio
AspectRatio::ConvertToWritingMode(
2118 const WritingMode
& aWM
) const {
2119 return aWM
.IsVertical() ? Inverted() : *this;
2122 } // namespace mozilla
2124 // Definitions of inline methods for nsStylePosition, declared in
2125 // nsStyleStruct.h but not defined there because they need WritingMode.
2126 inline const mozilla::StyleSize
& nsStylePosition::ISize(WritingMode aWM
) const {
2127 return aWM
.IsVertical() ? mHeight
: mWidth
;
2129 inline const mozilla::StyleSize
& nsStylePosition::MinISize(
2130 WritingMode aWM
) const {
2131 return aWM
.IsVertical() ? mMinHeight
: mMinWidth
;
2133 inline const mozilla::StyleMaxSize
& nsStylePosition::MaxISize(
2134 WritingMode aWM
) const {
2135 return aWM
.IsVertical() ? mMaxHeight
: mMaxWidth
;
2137 inline const mozilla::StyleSize
& nsStylePosition::BSize(WritingMode aWM
) const {
2138 return aWM
.IsVertical() ? mWidth
: mHeight
;
2140 inline const mozilla::StyleSize
& nsStylePosition::MinBSize(
2141 WritingMode aWM
) const {
2142 return aWM
.IsVertical() ? mMinWidth
: mMinHeight
;
2144 inline const mozilla::StyleMaxSize
& nsStylePosition::MaxBSize(
2145 WritingMode aWM
) const {
2146 return aWM
.IsVertical() ? mMaxWidth
: mMaxHeight
;
2148 inline const mozilla::StyleSize
& nsStylePosition::Size(
2149 mozilla::LogicalAxis aAxis
, WritingMode aWM
) const {
2150 return aAxis
== mozilla::eLogicalAxisInline
? ISize(aWM
) : BSize(aWM
);
2152 inline const mozilla::StyleSize
& nsStylePosition::MinSize(
2153 mozilla::LogicalAxis aAxis
, WritingMode aWM
) const {
2154 return aAxis
== mozilla::eLogicalAxisInline
? MinISize(aWM
) : MinBSize(aWM
);
2156 inline const mozilla::StyleMaxSize
& nsStylePosition::MaxSize(
2157 mozilla::LogicalAxis aAxis
, WritingMode aWM
) const {
2158 return aAxis
== mozilla::eLogicalAxisInline
? MaxISize(aWM
) : MaxBSize(aWM
);
2161 inline bool nsStylePosition::ISizeDependsOnContainer(WritingMode aWM
) const {
2162 const auto& iSize
= ISize(aWM
);
2163 return iSize
.IsAuto() || ISizeCoordDependsOnContainer(iSize
);
2165 inline bool nsStylePosition::MinISizeDependsOnContainer(WritingMode aWM
) const {
2166 // NOTE: For a flex item, "min-inline-size:auto" is supposed to behave like
2167 // "min-content", which does depend on the container, so you might think we'd
2168 // need a special case for "flex item && min-inline-size:auto" here. However,
2169 // we don't actually need that special-case code, because flex items are
2170 // explicitly supposed to *ignore* their min-inline-size (i.e. behave like
2171 // it's 0) until the flex container explicitly considers it. So -- since the
2172 // flex container doesn't rely on this method, we don't need to worry about
2173 // special behavior for flex items' "min-inline-size:auto" values here.
2174 return ISizeCoordDependsOnContainer(MinISize(aWM
));
2176 inline bool nsStylePosition::MaxISizeDependsOnContainer(WritingMode aWM
) const {
2177 // NOTE: The comment above MinISizeDependsOnContainer about flex items
2178 // applies here, too.
2179 return ISizeCoordDependsOnContainer(MaxISize(aWM
));
2181 // Note that these functions count `auto` as depending on the container
2182 // since that's the case for absolutely positioned elements.
2183 // However, some callers do not care about this case and should check
2184 // for it, since it is the most common case.
2185 // FIXME: We should probably change the assumption to be the other way
2187 inline bool nsStylePosition::BSizeDependsOnContainer(WritingMode aWM
) const {
2188 const auto& bSize
= BSize(aWM
);
2189 return bSize
.BehavesLikeInitialValueOnBlockAxis() ||
2190 BSizeCoordDependsOnContainer(bSize
);
2192 inline bool nsStylePosition::MinBSizeDependsOnContainer(WritingMode aWM
) const {
2193 return BSizeCoordDependsOnContainer(MinBSize(aWM
));
2195 inline bool nsStylePosition::MaxBSizeDependsOnContainer(WritingMode aWM
) const {
2196 return BSizeCoordDependsOnContainer(MaxBSize(aWM
));
2199 inline bool nsStyleMargin::HasBlockAxisAuto(mozilla::WritingMode aWM
) const {
2200 return mMargin
.GetBStart(aWM
).IsAuto() || mMargin
.GetBEnd(aWM
).IsAuto();
2203 inline bool nsStyleMargin::HasInlineAxisAuto(mozilla::WritingMode aWM
) const {
2204 return mMargin
.GetIStart(aWM
).IsAuto() || mMargin
.GetIEnd(aWM
).IsAuto();
2206 inline bool nsStyleMargin::HasAuto(mozilla::LogicalAxis aAxis
,
2207 mozilla::WritingMode aWM
) const {
2208 return aAxis
== mozilla::eLogicalAxisInline
? HasInlineAxisAuto(aWM
)
2209 : HasBlockAxisAuto(aWM
);
2212 inline mozilla::StyleAlignFlags
nsStylePosition::UsedSelfAlignment(
2213 mozilla::LogicalAxis aAxis
, const mozilla::ComputedStyle
* aParent
) const {
2214 return aAxis
== mozilla::eLogicalAxisBlock
? UsedAlignSelf(aParent
)._0
2215 : UsedJustifySelf(aParent
)._0
;
2218 inline mozilla::StyleContentDistribution
nsStylePosition::UsedContentAlignment(
2219 mozilla::LogicalAxis aAxis
) const {
2220 return aAxis
== mozilla::eLogicalAxisBlock
? mAlignContent
: mJustifyContent
;
2223 inline mozilla::StyleContentDistribution
nsStylePosition::UsedTracksAlignment(
2224 mozilla::LogicalAxis aAxis
, uint32_t aIndex
) const {
2225 using T
= mozilla::StyleAlignFlags
;
2226 const auto& tracksAlignment
=
2227 aAxis
== mozilla::eLogicalAxisBlock
? mAlignTracks
: mJustifyTracks
;
2228 if (MOZ_LIKELY(tracksAlignment
.IsEmpty())) {
2229 // An empty array encodes the initial value, 'normal', which behaves as
2230 // 'start' for Grid containers.
2231 return mozilla::StyleContentDistribution
{T::START
};
2234 // If there are fewer values than tracks, then the last value is used for all
2235 // the remaining tracks.
2236 const auto& ta
= tracksAlignment
.AsSpan();
2237 auto align
= ta
[std::min
<size_t>(aIndex
, ta
.Length() - 1)];
2238 if (align
.primary
== T::NORMAL
) {
2239 align
= mozilla::StyleContentDistribution
{T::START
};
2244 #endif // WritingModes_h_