Line data Source code
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/. */
5 :
6 : #ifndef WritingModes_h_
7 : #define WritingModes_h_
8 :
9 : #include "nsRect.h"
10 : #include "nsStyleContext.h"
11 : #include "nsStyleContextInlines.h"
12 : #include "nsBidiUtils.h"
13 :
14 : // It is the caller's responsibility to operate on logical-coordinate objects
15 : // with matched writing modes. Failure to do so will be a runtime bug; the
16 : // compiler can't catch it, but in debug mode, we'll throw an assertion.
17 : // NOTE that in non-debug builds, a writing mode mismatch error will NOT be
18 : // detected, yet the results will be nonsense (and may lead to further layout
19 : // failures). Therefore, it is important to test (and fuzz-test) writing-mode
20 : // support using debug builds.
21 :
22 : // Methods in logical-coordinate classes that take another logical-coordinate
23 : // object as a parameter should call CHECK_WRITING_MODE on it to verify that
24 : // the writing modes match.
25 : // (In some cases, there are internal (private) methods that don't do this;
26 : // such methods should only be used by other methods that have already checked
27 : // the writing modes.)
28 : // The check ignores the eSidewaysMask bit of writing mode, because this does
29 : // not affect the interpretation of logical coordinates.
30 :
31 : #define CHECK_WRITING_MODE(param) \
32 : NS_ASSERTION(param.IgnoreSideways() == GetWritingMode().IgnoreSideways(), \
33 : "writing-mode mismatch")
34 :
35 : namespace mozilla {
36 :
37 : namespace widget {
38 : struct IMENotification;
39 : } // namespace widget
40 :
41 : // Physical axis constants.
42 : enum PhysicalAxis {
43 : eAxisVertical = 0x0,
44 : eAxisHorizontal = 0x1
45 : };
46 :
47 0 : inline LogicalAxis GetOrthogonalAxis(LogicalAxis aAxis)
48 : {
49 0 : return aAxis == eLogicalAxisBlock ? eLogicalAxisInline : eLogicalAxisBlock;
50 : }
51 :
52 2482 : inline bool IsInline(LogicalSide aSide) { return aSide & 0x2; }
53 2482 : inline bool IsBlock(LogicalSide aSide) { return !IsInline(aSide); }
54 2482 : inline bool IsEnd(LogicalSide aSide) { return aSide & 0x1; }
55 : inline bool IsStart(LogicalSide aSide) { return !IsEnd(aSide); }
56 :
57 0 : inline LogicalAxis GetAxis(LogicalSide aSide)
58 : {
59 0 : return IsInline(aSide) ? eLogicalAxisInline : eLogicalAxisBlock;
60 : }
61 :
62 2482 : inline LogicalEdge GetEdge(LogicalSide aSide)
63 : {
64 2482 : return IsEnd(aSide) ? eLogicalEdgeEnd : eLogicalEdgeStart;
65 : }
66 :
67 0 : inline LogicalEdge GetOppositeEdge(LogicalEdge aEdge)
68 : {
69 : // This relies on the only two LogicalEdge enum values being 0 and 1.
70 0 : return LogicalEdge(1 - aEdge);
71 : }
72 :
73 : inline LogicalSide
74 154 : MakeLogicalSide(LogicalAxis aAxis, LogicalEdge aEdge)
75 : {
76 154 : return LogicalSide((aAxis << 1) | aEdge);
77 : }
78 :
79 0 : inline LogicalSide GetOppositeSide(LogicalSide aSide)
80 : {
81 0 : return MakeLogicalSide(GetAxis(aSide), GetOppositeEdge(GetEdge(aSide)));
82 : }
83 :
84 : enum LogicalSideBits {
85 : eLogicalSideBitsNone = 0,
86 : eLogicalSideBitsBStart = 1 << eLogicalSideBStart,
87 : eLogicalSideBitsBEnd = 1 << eLogicalSideBEnd,
88 : eLogicalSideBitsIEnd = 1 << eLogicalSideIEnd,
89 : eLogicalSideBitsIStart = 1 << eLogicalSideIStart,
90 : eLogicalSideBitsBBoth = eLogicalSideBitsBStart | eLogicalSideBitsBEnd,
91 : eLogicalSideBitsIBoth = eLogicalSideBitsIStart | eLogicalSideBitsIEnd,
92 : eLogicalSideBitsAll = eLogicalSideBitsBBoth | eLogicalSideBitsIBoth
93 : };
94 :
95 : enum LineRelativeDir {
96 : eLineRelativeDirOver = eLogicalSideBStart,
97 : eLineRelativeDirUnder = eLogicalSideBEnd,
98 : eLineRelativeDirLeft = eLogicalSideIStart,
99 : eLineRelativeDirRight = eLogicalSideIEnd
100 : };
101 :
102 : /**
103 : * LogicalSides represents a set of logical sides.
104 : */
105 : struct LogicalSides final {
106 2398 : LogicalSides() : mBits(0) {}
107 0 : explicit LogicalSides(LogicalSideBits aSideBits)
108 0 : {
109 0 : MOZ_ASSERT((aSideBits & ~eLogicalSideBitsAll) == 0, "illegal side bits");
110 0 : mBits = aSideBits;
111 0 : }
112 : bool IsEmpty() const { return mBits == 0; }
113 2550 : bool BStart() const { return mBits & eLogicalSideBitsBStart; }
114 2550 : bool BEnd() const { return mBits & eLogicalSideBitsBEnd; }
115 2398 : bool IStart() const { return mBits & eLogicalSideBitsIStart; }
116 2398 : bool IEnd() const { return mBits & eLogicalSideBitsIEnd; }
117 : bool Contains(LogicalSideBits aSideBits) const
118 : {
119 : MOZ_ASSERT((aSideBits & ~eLogicalSideBitsAll) == 0, "illegal side bits");
120 : return (mBits & aSideBits) == aSideBits;
121 : }
122 0 : LogicalSides operator|(LogicalSides aOther) const
123 : {
124 0 : return LogicalSides(LogicalSideBits(mBits | aOther.mBits));
125 : }
126 : LogicalSides operator|(LogicalSideBits aSideBits) const
127 : {
128 : return *this | LogicalSides(aSideBits);
129 : }
130 0 : LogicalSides& operator|=(LogicalSides aOther)
131 : {
132 0 : mBits |= aOther.mBits;
133 0 : return *this;
134 : }
135 0 : LogicalSides& operator|=(LogicalSideBits aSideBits)
136 : {
137 0 : return *this |= LogicalSides(aSideBits);
138 : }
139 0 : bool operator==(LogicalSides aOther) const
140 : {
141 0 : return mBits == aOther.mBits;
142 : }
143 0 : bool operator!=(LogicalSides aOther) const
144 : {
145 0 : return !(*this == aOther);
146 : }
147 :
148 : private:
149 : uint8_t mBits;
150 : };
151 :
152 : /**
153 : * mozilla::WritingMode is an immutable class representing a
154 : * writing mode.
155 : *
156 : * It efficiently stores the writing mode and can rapidly compute
157 : * interesting things about it for use in layout.
158 : *
159 : * Writing modes are computed from the CSS 'direction',
160 : * 'writing-mode', and 'text-orientation' properties.
161 : * See CSS3 Writing Modes for more information
162 : * http://www.w3.org/TR/css3-writing-modes/
163 : */
164 : class WritingMode {
165 : public:
166 : /**
167 : * Absolute inline flow direction
168 : */
169 : enum InlineDir {
170 : eInlineLTR = 0x00, // text flows horizontally left to right
171 : eInlineRTL = 0x02, // text flows horizontally right to left
172 : eInlineTTB = 0x01, // text flows vertically top to bottom
173 : eInlineBTT = 0x03, // text flows vertically bottom to top
174 : };
175 :
176 : /**
177 : * Absolute block flow direction
178 : */
179 : enum BlockDir {
180 : eBlockTB = 0x00, // horizontal lines stack top to bottom
181 : eBlockRL = 0x01, // vertical lines stack right to left
182 : eBlockLR = 0x05, // vertical lines stack left to right
183 : };
184 :
185 : /**
186 : * Line-relative (bidi-relative) inline flow direction
187 : */
188 : enum BidiDir {
189 : eBidiLTR = 0x00, // inline flow matches bidi LTR text
190 : eBidiRTL = 0x10, // inline flow matches bidi RTL text
191 : };
192 :
193 : /**
194 : * Unknown writing mode (should never actually be stored or used anywhere).
195 : */
196 : enum {
197 : eUnknownWritingMode = 0xff
198 : };
199 :
200 : /**
201 : * Return the absolute inline flow direction as an InlineDir
202 : */
203 0 : InlineDir GetInlineDir() const { return InlineDir(mWritingMode & eInlineMask); }
204 :
205 : /**
206 : * Return the absolute block flow direction as a BlockDir
207 : */
208 1790 : BlockDir GetBlockDir() const { return BlockDir(mWritingMode & eBlockMask); }
209 :
210 : /**
211 : * Return the line-relative inline flow direction as a BidiDir
212 : */
213 3372 : BidiDir GetBidiDir() const { return BidiDir(mWritingMode & eBidiMask); }
214 :
215 : /**
216 : * Return true if the inline flow direction is against physical direction
217 : * (i.e. right-to-left or bottom-to-top).
218 : * This occurs when writing-mode is sideways-lr OR direction is rtl (but not
219 : * if both of those are true).
220 : */
221 9140 : bool IsInlineReversed() const { return !!(mWritingMode & eInlineFlowMask); }
222 :
223 : /**
224 : * Return true if bidi direction is LTR. (Convenience method)
225 : */
226 3372 : bool IsBidiLTR() const { return eBidiLTR == GetBidiDir(); }
227 :
228 : /**
229 : * True if vertical-mode block direction is LR (convenience method).
230 : */
231 0 : bool IsVerticalLR() const { return eBlockLR == GetBlockDir(); }
232 :
233 : /**
234 : * True if vertical-mode block direction is RL (convenience method).
235 : */
236 1016 : bool IsVerticalRL() const { return eBlockRL == GetBlockDir(); }
237 :
238 : /**
239 : * True if vertical writing mode, i.e. when
240 : * writing-mode: vertical-lr | vertical-rl.
241 : */
242 58890 : bool IsVertical() const { return !!(mWritingMode & eOrientationMask); }
243 :
244 : /**
245 : * True if line-over/line-under are inverted from block-start/block-end.
246 : * This is true only when writing-mode is vertical-lr.
247 : */
248 770 : bool IsLineInverted() const { return !!(mWritingMode & eLineOrientMask); }
249 :
250 : /**
251 : * Block-axis flow-relative to line-relative factor.
252 : * May be used as a multiplication factor for block-axis coordinates
253 : * to convert between flow- and line-relative coordinate systems (e.g.
254 : * positioning an over- or under-line decoration).
255 : */
256 0 : int FlowRelativeToLineRelativeFactor() const
257 : {
258 0 : return IsLineInverted() ? -1 : 1;
259 : }
260 :
261 : /**
262 : * True if the text-orientation will force all text to be rendered sideways
263 : * in vertical lines, in which case we should prefer an alphabetic baseline;
264 : * otherwise, the default is centered.
265 : * Note that some glyph runs may be rendered sideways even if this is false,
266 : * due to text-orientation:mixed resolution, but in that case the dominant
267 : * baseline remains centered.
268 : */
269 0 : bool IsSideways() const { return !!(mWritingMode & eSidewaysMask); }
270 :
271 : #ifdef DEBUG // Used by CHECK_WRITING_MODE to compare modes without regard
272 : // for the eSidewaysMask flag.
273 79918 : WritingMode IgnoreSideways() const {
274 79918 : return WritingMode(mWritingMode & ~eSidewaysMask);
275 : }
276 : #endif
277 :
278 : /**
279 : * Return true if boxes with this writing mode should use central baselines.
280 : */
281 30 : bool IsCentralBaseline() const { return IsVertical() && !IsSideways(); }
282 :
283 : /**
284 : * Return true if boxes with this writing mode should use alphabetical
285 : * baselines.
286 : */
287 30 : bool IsAlphabeticalBaseline() const { return !IsCentralBaseline(); }
288 :
289 :
290 50 : static mozilla::PhysicalAxis PhysicalAxisForLogicalAxis(
291 : uint8_t aWritingModeValue,
292 : LogicalAxis aAxis)
293 : {
294 : // This relies on bit 0 of a writing-value mode indicating vertical
295 : // orientation and bit 0 of a LogicalAxis value indicating the inline axis,
296 : // so that it can correctly form mozilla::PhysicalAxis values using bit
297 : // manipulation.
298 : static_assert(NS_STYLE_WRITING_MODE_HORIZONTAL_TB == 0 &&
299 : NS_STYLE_WRITING_MODE_VERTICAL_RL == 1 &&
300 : NS_STYLE_WRITING_MODE_VERTICAL_LR == 3 &&
301 : eLogicalAxisBlock == 0 &&
302 : eLogicalAxisInline == 1 &&
303 : eAxisVertical == 0 &&
304 : eAxisHorizontal == 1,
305 : "unexpected writing-mode, logical axis or physical axis "
306 : "constant values");
307 50 : return mozilla::PhysicalAxis((aWritingModeValue ^ aAxis) & 0x1);
308 : }
309 :
310 50 : mozilla::PhysicalAxis PhysicalAxis(LogicalAxis aAxis) const
311 : {
312 : // This will set wm to either NS_STYLE_WRITING_MODE_HORIZONTAL_TB or
313 : // NS_STYLE_WRITING_MODE_VERTICAL_RL, and not the other two (real
314 : // and hypothetical) values. But this is fine; we only need to
315 : // distinguish between vertical and horizontal in
316 : // PhysicalAxisForLogicalAxis.
317 50 : int wm = mWritingMode & eOrientationMask;
318 50 : return PhysicalAxisForLogicalAxis(wm, aAxis);
319 : }
320 :
321 2174 : static mozilla::Side PhysicalSideForBlockAxis(uint8_t aWritingModeValue,
322 : LogicalEdge aEdge)
323 : {
324 : // indexes are NS_STYLE_WRITING_MODE_* values, which are the same as these
325 : // two-bit values:
326 : // bit 0 = the eOrientationMask value
327 : // bit 1 = the eBlockFlowMask value
328 : static const mozilla::Side kLogicalBlockSides[][2] = {
329 : { eSideTop, eSideBottom }, // horizontal-tb
330 : { eSideRight, eSideLeft }, // vertical-rl
331 : { eSideBottom, eSideTop }, // (horizontal-bt)
332 : { eSideLeft, eSideRight }, // vertical-lr
333 : };
334 :
335 : // Ignore the SIDEWAYS_MASK bit of the writing-mode value, as this has no
336 : // effect on the side mappings.
337 2174 : aWritingModeValue &= ~NS_STYLE_WRITING_MODE_SIDEWAYS_MASK;
338 :
339 : // What's left of the writing-mode should be in the range 0-3:
340 2174 : NS_ASSERTION(aWritingModeValue < 4, "invalid aWritingModeValue value");
341 :
342 2174 : return kLogicalBlockSides[aWritingModeValue][aEdge];
343 : }
344 :
345 510 : mozilla::Side PhysicalSideForInlineAxis(LogicalEdge aEdge) const
346 : {
347 : // indexes are four-bit values:
348 : // bit 0 = the eOrientationMask value
349 : // bit 1 = the eInlineFlowMask value
350 : // bit 2 = the eBlockFlowMask value
351 : // bit 3 = the eLineOrientMask value
352 : // Not all of these combinations can actually be specified via CSS: there
353 : // is no horizontal-bt writing-mode, and no text-orientation value that
354 : // produces "inverted" text. (The former 'sideways-left' value, no longer
355 : // in the spec, would have produced this in vertical-rl mode.)
356 : static const mozilla::Side kLogicalInlineSides[][2] = {
357 : { eSideLeft, eSideRight }, // horizontal-tb ltr
358 : { eSideTop, eSideBottom }, // vertical-rl ltr
359 : { eSideRight, eSideLeft }, // horizontal-tb rtl
360 : { eSideBottom, eSideTop }, // vertical-rl rtl
361 : { eSideRight, eSideLeft }, // (horizontal-bt) (inverted) ltr
362 : { eSideTop, eSideBottom }, // sideways-lr rtl
363 : { eSideLeft, eSideRight }, // (horizontal-bt) (inverted) rtl
364 : { eSideBottom, eSideTop }, // sideways-lr ltr
365 : { eSideLeft, eSideRight }, // horizontal-tb (inverted) rtl
366 : { eSideTop, eSideBottom }, // vertical-rl (inverted) rtl
367 : { eSideRight, eSideLeft }, // horizontal-tb (inverted) ltr
368 : { eSideBottom, eSideTop }, // vertical-rl (inverted) ltr
369 : { eSideLeft, eSideRight }, // (horizontal-bt) ltr
370 : { eSideTop, eSideBottom }, // vertical-lr ltr
371 : { eSideRight, eSideLeft }, // (horizontal-bt) rtl
372 : { eSideBottom, eSideTop }, // vertical-lr rtl
373 : };
374 :
375 : // Inline axis sides depend on all three of writing-mode, text-orientation
376 : // and direction, which are encoded in the eOrientationMask,
377 : // eInlineFlowMask, eBlockFlowMask and eLineOrientMask bits. Use these four
378 : // bits to index into kLogicalInlineSides.
379 : static_assert(eOrientationMask == 0x01 && eInlineFlowMask == 0x02 &&
380 : eBlockFlowMask == 0x04 && eLineOrientMask == 0x08,
381 : "unexpected mask values");
382 510 : int index = mWritingMode & 0x0F;
383 510 : return kLogicalInlineSides[index][aEdge];
384 : }
385 :
386 : /**
387 : * Returns the physical side corresponding to the specified logical side,
388 : * given the current writing mode.
389 : */
390 2482 : mozilla::Side PhysicalSide(LogicalSide aSide) const
391 : {
392 2482 : if (IsBlock(aSide)) {
393 : static_assert(eOrientationMask == 0x01 && eBlockFlowMask == 0x04,
394 : "unexpected mask values");
395 2174 : int wm = ((mWritingMode & eBlockFlowMask) >> 1) |
396 2174 : (mWritingMode & eOrientationMask);
397 2174 : return PhysicalSideForBlockAxis(wm, GetEdge(aSide));
398 : }
399 :
400 308 : return PhysicalSideForInlineAxis(GetEdge(aSide));
401 : }
402 :
403 : /**
404 : * Returns the logical side corresponding to the specified physical side,
405 : * given the current writing mode.
406 : * (This is the inverse of the PhysicalSide() method above.)
407 : */
408 0 : LogicalSide LogicalSideForPhysicalSide(mozilla::Side aSide) const
409 : {
410 : // indexes are four-bit values:
411 : // bit 0 = the eOrientationMask value
412 : // bit 1 = the eInlineFlowMask value
413 : // bit 2 = the eBlockFlowMask value
414 : // bit 3 = the eLineOrientMask value
415 : static const LogicalSide kPhysicalToLogicalSides[][4] = {
416 : // top right
417 : // bottom left
418 : { eLogicalSideBStart, eLogicalSideIEnd,
419 : eLogicalSideBEnd, eLogicalSideIStart }, // horizontal-tb ltr
420 : { eLogicalSideIStart, eLogicalSideBStart,
421 : eLogicalSideIEnd, eLogicalSideBEnd }, // vertical-rl ltr
422 : { eLogicalSideBStart, eLogicalSideIStart,
423 : eLogicalSideBEnd, eLogicalSideIEnd }, // horizontal-tb rtl
424 : { eLogicalSideIEnd, eLogicalSideBStart,
425 : eLogicalSideIStart, eLogicalSideBEnd }, // vertical-rl rtl
426 : { eLogicalSideBEnd, eLogicalSideIStart,
427 : eLogicalSideBStart, eLogicalSideIEnd }, // (horizontal-bt) (inv) ltr
428 : { eLogicalSideIStart, eLogicalSideBEnd,
429 : eLogicalSideIEnd, eLogicalSideBStart }, // vertical-lr sw-left rtl
430 : { eLogicalSideBEnd, eLogicalSideIEnd,
431 : eLogicalSideBStart, eLogicalSideIStart }, // (horizontal-bt) (inv) rtl
432 : { eLogicalSideIEnd, eLogicalSideBEnd,
433 : eLogicalSideIStart, eLogicalSideBStart }, // vertical-lr sw-left ltr
434 : { eLogicalSideBStart, eLogicalSideIEnd,
435 : eLogicalSideBEnd, eLogicalSideIStart }, // horizontal-tb (inv) rtl
436 : { eLogicalSideIStart, eLogicalSideBStart,
437 : eLogicalSideIEnd, eLogicalSideBEnd }, // vertical-rl sw-left rtl
438 : { eLogicalSideBStart, eLogicalSideIStart,
439 : eLogicalSideBEnd, eLogicalSideIEnd }, // horizontal-tb (inv) ltr
440 : { eLogicalSideIEnd, eLogicalSideBStart,
441 : eLogicalSideIStart, eLogicalSideBEnd }, // vertical-rl sw-left ltr
442 : { eLogicalSideBEnd, eLogicalSideIEnd,
443 : eLogicalSideBStart, eLogicalSideIStart }, // (horizontal-bt) ltr
444 : { eLogicalSideIStart, eLogicalSideBEnd,
445 : eLogicalSideIEnd, eLogicalSideBStart }, // vertical-lr ltr
446 : { eLogicalSideBEnd, eLogicalSideIStart,
447 : eLogicalSideBStart, eLogicalSideIEnd }, // (horizontal-bt) rtl
448 : { eLogicalSideIEnd, eLogicalSideBEnd,
449 : eLogicalSideIStart, eLogicalSideBStart }, // vertical-lr rtl
450 : };
451 :
452 : static_assert(eOrientationMask == 0x01 && eInlineFlowMask == 0x02 &&
453 : eBlockFlowMask == 0x04 && eLineOrientMask == 0x08,
454 : "unexpected mask values");
455 0 : int index = mWritingMode & 0x0F;
456 0 : return kPhysicalToLogicalSides[index][aSide];
457 : }
458 :
459 : /**
460 : * Returns the logical side corresponding to the specified
461 : * line-relative direction, given the current writing mode.
462 : */
463 0 : LogicalSide LogicalSideForLineRelativeDir(LineRelativeDir aDir) const
464 : {
465 0 : auto side = static_cast<LogicalSide>(aDir);
466 0 : if (IsInline(side)) {
467 0 : return IsBidiLTR() ? side : GetOppositeSide(side);
468 : }
469 0 : return !IsLineInverted() ? side : GetOppositeSide(side);
470 : }
471 :
472 : /**
473 : * Default constructor gives us a horizontal, LTR writing mode.
474 : * XXX We will probably eliminate this and require explicit initialization
475 : * in all cases once transition is complete.
476 : */
477 892 : WritingMode()
478 892 : : mWritingMode(0)
479 892 : { }
480 :
481 : /**
482 : * Construct writing mode based on a style context
483 : */
484 1805 : explicit WritingMode(nsStyleContext* aStyleContext)
485 1805 : {
486 1805 : NS_ASSERTION(aStyleContext, "we need an nsStyleContext here");
487 1805 : InitFromStyleVisibility(aStyleContext->StyleVisibility());
488 1805 : }
489 :
490 289 : explicit WritingMode(const nsStyleVisibility* aStyleVisibility)
491 289 : {
492 289 : NS_ASSERTION(aStyleVisibility, "we need an nsStyleVisibility here");
493 289 : InitFromStyleVisibility(aStyleVisibility);
494 289 : }
495 :
496 : private:
497 2094 : void InitFromStyleVisibility(const nsStyleVisibility* aStyleVisibility)
498 : {
499 2094 : switch (aStyleVisibility->mWritingMode) {
500 : case NS_STYLE_WRITING_MODE_HORIZONTAL_TB:
501 2094 : mWritingMode = 0;
502 2094 : break;
503 :
504 : case NS_STYLE_WRITING_MODE_VERTICAL_LR:
505 : {
506 0 : mWritingMode = eBlockFlowMask |
507 : eLineOrientMask |
508 : eOrientationMask;
509 0 : uint8_t textOrientation = aStyleVisibility->mTextOrientation;
510 0 : if (textOrientation == NS_STYLE_TEXT_ORIENTATION_SIDEWAYS) {
511 0 : mWritingMode |= eSidewaysMask;
512 : }
513 0 : break;
514 : }
515 :
516 : case NS_STYLE_WRITING_MODE_VERTICAL_RL:
517 : {
518 0 : mWritingMode = eOrientationMask;
519 0 : uint8_t textOrientation = aStyleVisibility->mTextOrientation;
520 0 : if (textOrientation == NS_STYLE_TEXT_ORIENTATION_SIDEWAYS) {
521 0 : mWritingMode |= eSidewaysMask;
522 : }
523 0 : break;
524 : }
525 :
526 : case NS_STYLE_WRITING_MODE_SIDEWAYS_LR:
527 0 : mWritingMode = eBlockFlowMask |
528 : eInlineFlowMask |
529 : eOrientationMask |
530 : eSidewaysMask;
531 0 : break;
532 :
533 : case NS_STYLE_WRITING_MODE_SIDEWAYS_RL:
534 0 : mWritingMode = eOrientationMask |
535 : eSidewaysMask;
536 0 : break;
537 :
538 : default:
539 0 : NS_NOTREACHED("unknown writing mode!");
540 0 : mWritingMode = 0;
541 0 : break;
542 : }
543 :
544 2094 : if (NS_STYLE_DIRECTION_RTL == aStyleVisibility->mDirection) {
545 0 : mWritingMode ^= eInlineFlowMask | eBidiMask;
546 : }
547 2094 : }
548 : public:
549 :
550 : /**
551 : * This function performs fixup for elements with 'unicode-bidi: plaintext',
552 : * where inline directionality is derived from the Unicode bidi categories
553 : * of the element's content, and not the CSS 'direction' property.
554 : *
555 : * The WritingMode constructor will have already incorporated the 'direction'
556 : * property into our flag bits, so such elements need to use this method
557 : * (after resolving the bidi level of their content) to update the direction
558 : * bits as needed.
559 : *
560 : * If it turns out that our bidi direction already matches what plaintext
561 : * resolution determined, there's nothing to do here. If it didn't (i.e. if
562 : * the rtl-ness doesn't match), then we correct the direction by flipping the
563 : * same bits that get flipped in the constructor's CSS 'direction'-based
564 : * chunk.
565 : *
566 : * XXX change uint8_t to UBiDiLevel after bug 924851
567 : */
568 1642 : void SetDirectionFromBidiLevel(uint8_t level)
569 : {
570 1642 : if (IS_LEVEL_RTL(level) == IsBidiLTR()) {
571 0 : mWritingMode ^= eBidiMask | eInlineFlowMask;
572 : }
573 1642 : }
574 :
575 : /**
576 : * Compare two WritingModes for equality.
577 : */
578 43987 : bool operator==(const WritingMode& aOther) const
579 : {
580 43987 : return mWritingMode == aOther.mWritingMode;
581 : }
582 :
583 : bool operator!=(const WritingMode& aOther) const
584 : {
585 : return mWritingMode != aOther.mWritingMode;
586 : }
587 :
588 : /**
589 : * Check whether two modes are orthogonal to each other.
590 : */
591 4781 : bool IsOrthogonalTo(const WritingMode& aOther) const
592 : {
593 4781 : return IsVertical() != aOther.IsVertical();
594 : }
595 :
596 : /**
597 : * Returns true if this WritingMode's aLogicalAxis has the same physical
598 : * start side as the parallel axis of WritingMode |aOther|.
599 : *
600 : * @param aLogicalAxis The axis to compare from this WritingMode.
601 : * @param aOther The other WritingMode (from which we'll choose the axis
602 : * that's parallel to this WritingMode's aLogicalAxis, for
603 : * comparison).
604 : */
605 0 : bool ParallelAxisStartsOnSameSide(LogicalAxis aLogicalAxis,
606 : const WritingMode& aOther) const
607 : {
608 : Side myStartSide =
609 0 : this->PhysicalSide(MakeLogicalSide(aLogicalAxis,
610 0 : eLogicalEdgeStart));
611 :
612 : // Figure out which of aOther's axes is parallel to |this| WritingMode's
613 : // aLogicalAxis, and get its physical start side as well.
614 0 : LogicalAxis otherWMAxis = aOther.IsOrthogonalTo(*this) ?
615 0 : GetOrthogonalAxis(aLogicalAxis) : aLogicalAxis;
616 : Side otherWMStartSide =
617 0 : aOther.PhysicalSide(MakeLogicalSide(otherWMAxis,
618 0 : eLogicalEdgeStart));
619 :
620 0 : NS_ASSERTION(myStartSide % 2 == otherWMStartSide % 2,
621 : "Should end up with sides in the same physical axis");
622 0 : return myStartSide == otherWMStartSide;
623 : }
624 :
625 241 : uint8_t GetBits() const { return mWritingMode; }
626 :
627 0 : const char* DebugString() const {
628 0 : return IsVertical()
629 0 : ? IsVerticalLR()
630 0 : ? IsBidiLTR()
631 0 : ? IsSideways() ? "sw-lr-ltr" : "v-lr-ltr"
632 0 : : IsSideways() ? "sw-lr-rtl" : "v-lr-rtl"
633 0 : : IsBidiLTR()
634 0 : ? IsSideways() ? "sw-rl-ltr" : "v-rl-ltr"
635 0 : : IsSideways() ? "sw-rl-rtl" : "v-rl-rtl"
636 0 : : IsBidiLTR() ? "h-ltr" : "h-rtl"
637 : ;
638 : }
639 :
640 : private:
641 : friend class LogicalPoint;
642 : friend class LogicalSize;
643 : friend class LogicalMargin;
644 : friend class LogicalRect;
645 :
646 : friend struct IPC::ParamTraits<WritingMode>;
647 : // IMENotification cannot store this class directly since this has some
648 : // constructors. Therefore, it stores mWritingMode and recreate the
649 : // instance from it.
650 : friend struct widget::IMENotification;
651 :
652 : /**
653 : * Return a WritingMode representing an unknown value.
654 : */
655 : static inline WritingMode Unknown()
656 : {
657 : return WritingMode(eUnknownWritingMode);
658 : }
659 :
660 : /**
661 : * Constructing a WritingMode with an arbitrary value is a private operation
662 : * currently only used by the Unknown() static method.
663 : */
664 79918 : explicit WritingMode(uint8_t aValue)
665 79918 : : mWritingMode(aValue)
666 79918 : { }
667 :
668 : uint8_t mWritingMode;
669 :
670 : enum Masks {
671 : // Masks for our bits; true chosen as opposite of commonest case
672 : eOrientationMask = 0x01, // true means vertical text
673 : eInlineFlowMask = 0x02, // true means absolute RTL/BTT (against physical coords)
674 : eBlockFlowMask = 0x04, // true means vertical-LR (or horizontal-BT if added)
675 : eLineOrientMask = 0x08, // true means over != block-start
676 : eBidiMask = 0x10, // true means line-relative RTL (bidi RTL)
677 : // Note: We have one excess bit of info; WritingMode can pack into 4 bits.
678 : // But since we have space, we're caching interesting things for fast access.
679 :
680 : eSidewaysMask = 0x20, // true means text is being rendered vertically
681 : // using rotated glyphs (i.e. writing-mode is
682 : // sideways-*, or writing-mode is vertical-* AND
683 : // text-orientation is sideways),
684 : // which means we'll use alphabetic instead of
685 : // centered default baseline for vertical text
686 :
687 : // Masks for output enums
688 : eInlineMask = 0x03,
689 : eBlockMask = 0x05
690 : };
691 : };
692 :
693 :
694 : /**
695 : * Logical-coordinate classes:
696 : *
697 : * There are three sets of coordinate space:
698 : * - physical (top, left, bottom, right)
699 : * relative to graphics coord system
700 : * - flow-relative (block-start, inline-start, block-end, inline-end)
701 : * relative to block/inline flow directions
702 : * - line-relative (line-over, line-left, line-under, line-right)
703 : * relative to glyph orientation / inline bidi directions
704 : * See CSS3 Writing Modes for more information
705 : * http://www.w3.org/TR/css3-writing-modes/#abstract-box
706 : *
707 : * For shorthand, B represents the block-axis
708 : * I represents the inline-axis
709 : *
710 : * The flow-relative geometric classes store coords in flow-relative space.
711 : * They use a private ns{Point,Size,Rect,Margin} member to store the actual
712 : * coordinate values, but reinterpret them as logical instead of physical.
713 : * This allows us to easily perform calculations in logical space (provided
714 : * writing modes of the operands match), by simply mapping to nsPoint (etc)
715 : * methods.
716 : *
717 : * Physical-coordinate accessors/setters are responsible to translate these
718 : * internal logical values as necessary.
719 : *
720 : * In DEBUG builds, the logical types store their WritingMode and check
721 : * that the same WritingMode is passed whenever callers ask them to do a
722 : * writing-mode-dependent operation. Non-DEBUG builds do NOT check this,
723 : * to avoid the overhead of storing WritingMode fields.
724 : *
725 : * Open question: do we need a different set optimized for line-relative
726 : * math, for use in nsLineLayout and the like? Or is multiplying values
727 : * by FlowRelativeToLineRelativeFactor() enough?
728 : */
729 :
730 : /**
731 : * Flow-relative point
732 : */
733 10 : class LogicalPoint {
734 : public:
735 254 : explicit LogicalPoint(WritingMode aWritingMode)
736 254 : :
737 : #ifdef DEBUG
738 : mWritingMode(aWritingMode),
739 : #endif
740 254 : mPoint(0, 0)
741 254 : { }
742 :
743 : // Construct from a writing mode and individual coordinates (which MUST be
744 : // values in that writing mode, NOT physical coordinates!)
745 79 : LogicalPoint(WritingMode aWritingMode, nscoord aI, nscoord aB)
746 79 : :
747 : #ifdef DEBUG
748 : mWritingMode(aWritingMode),
749 : #endif
750 79 : mPoint(aI, aB)
751 79 : { }
752 :
753 : // Construct from a writing mode and a physical point, within a given
754 : // containing rectangle's size (defining the conversion between LTR
755 : // and RTL coordinates, and between TTB and BTT coordinates).
756 209 : LogicalPoint(WritingMode aWritingMode,
757 : const nsPoint& aPoint,
758 : const nsSize& aContainerSize)
759 : #ifdef DEBUG
760 209 : : mWritingMode(aWritingMode)
761 : #endif
762 : {
763 209 : if (aWritingMode.IsVertical()) {
764 0 : I() = aWritingMode.IsInlineReversed() ? aContainerSize.height - aPoint.y
765 : : aPoint.y;
766 0 : B() = aWritingMode.IsVerticalLR() ? aPoint.x
767 0 : : aContainerSize.width - aPoint.x;
768 : } else {
769 209 : I() = aWritingMode.IsInlineReversed() ? aContainerSize.width - aPoint.x
770 : : aPoint.x;
771 209 : B() = aPoint.y;
772 : }
773 209 : }
774 :
775 : /**
776 : * Read-only (const) access to the logical coordinates.
777 : */
778 0 : nscoord I(WritingMode aWritingMode) const // inline-axis
779 : {
780 0 : CHECK_WRITING_MODE(aWritingMode);
781 0 : return mPoint.x;
782 : }
783 0 : nscoord B(WritingMode aWritingMode) const // block-axis
784 : {
785 0 : CHECK_WRITING_MODE(aWritingMode);
786 0 : return mPoint.y;
787 : }
788 0 : nscoord LineRelative(WritingMode aWritingMode,
789 : const nsSize& aContainerSize) const // line-axis
790 : {
791 0 : CHECK_WRITING_MODE(aWritingMode);
792 0 : if (aWritingMode.IsBidiLTR()) {
793 0 : return I();
794 : }
795 0 : return (aWritingMode.IsVertical() ? aContainerSize.height
796 0 : : aContainerSize.width) - I();
797 : }
798 :
799 : /**
800 : * These non-const accessors return a reference (lvalue) that can be
801 : * assigned to by callers.
802 : */
803 77 : nscoord& I(WritingMode aWritingMode) // inline-axis
804 : {
805 77 : CHECK_WRITING_MODE(aWritingMode);
806 77 : return mPoint.x;
807 : }
808 154 : nscoord& B(WritingMode aWritingMode) // block-axis
809 : {
810 154 : CHECK_WRITING_MODE(aWritingMode);
811 154 : return mPoint.y;
812 : }
813 :
814 : /**
815 : * Return a physical point corresponding to our logical coordinates,
816 : * converted according to our writing mode.
817 : */
818 100 : nsPoint GetPhysicalPoint(WritingMode aWritingMode,
819 : const nsSize& aContainerSize) const
820 : {
821 100 : CHECK_WRITING_MODE(aWritingMode);
822 100 : if (aWritingMode.IsVertical()) {
823 0 : return nsPoint(aWritingMode.IsVerticalLR()
824 0 : ? B() : aContainerSize.width - B(),
825 0 : aWritingMode.IsInlineReversed()
826 0 : ? aContainerSize.height - I() : I());
827 : } else {
828 100 : return nsPoint(aWritingMode.IsInlineReversed()
829 0 : ? aContainerSize.width - I() : I(),
830 200 : B());
831 : }
832 : }
833 :
834 : /**
835 : * Return the equivalent point in a different writing mode.
836 : */
837 10 : LogicalPoint ConvertTo(WritingMode aToMode, WritingMode aFromMode,
838 : const nsSize& aContainerSize) const
839 : {
840 10 : CHECK_WRITING_MODE(aFromMode);
841 10 : return aToMode == aFromMode ?
842 : *this : LogicalPoint(aToMode,
843 10 : GetPhysicalPoint(aFromMode, aContainerSize),
844 30 : aContainerSize);
845 : }
846 :
847 0 : bool operator==(const LogicalPoint& aOther) const
848 : {
849 0 : CHECK_WRITING_MODE(aOther.GetWritingMode());
850 0 : return mPoint == aOther.mPoint;
851 : }
852 :
853 0 : bool operator!=(const LogicalPoint& aOther) const
854 : {
855 0 : CHECK_WRITING_MODE(aOther.GetWritingMode());
856 0 : return mPoint != aOther.mPoint;
857 : }
858 :
859 0 : LogicalPoint operator+(const LogicalPoint& aOther) const
860 : {
861 0 : CHECK_WRITING_MODE(aOther.GetWritingMode());
862 : // In non-debug builds, LogicalPoint does not store the WritingMode,
863 : // so the first parameter here (which will always be eUnknownWritingMode)
864 : // is ignored.
865 : return LogicalPoint(GetWritingMode(),
866 0 : mPoint.x + aOther.mPoint.x,
867 0 : mPoint.y + aOther.mPoint.y);
868 : }
869 :
870 0 : LogicalPoint& operator+=(const LogicalPoint& aOther)
871 : {
872 0 : CHECK_WRITING_MODE(aOther.GetWritingMode());
873 0 : I() += aOther.I();
874 0 : B() += aOther.B();
875 0 : return *this;
876 : }
877 :
878 0 : LogicalPoint operator-(const LogicalPoint& aOther) const
879 : {
880 0 : CHECK_WRITING_MODE(aOther.GetWritingMode());
881 : // In non-debug builds, LogicalPoint does not store the WritingMode,
882 : // so the first parameter here (which will always be eUnknownWritingMode)
883 : // is ignored.
884 : return LogicalPoint(GetWritingMode(),
885 0 : mPoint.x - aOther.mPoint.x,
886 0 : mPoint.y - aOther.mPoint.y);
887 : }
888 :
889 : LogicalPoint& operator-=(const LogicalPoint& aOther)
890 : {
891 : CHECK_WRITING_MODE(aOther.GetWritingMode());
892 : I() -= aOther.I();
893 : B() -= aOther.B();
894 : return *this;
895 : }
896 :
897 : private:
898 : friend class LogicalRect;
899 :
900 : /**
901 : * NOTE that in non-DEBUG builds, GetWritingMode() always returns
902 : * eUnknownWritingMode, as the current mode is not stored in the logical-
903 : * geometry classes. Therefore, this method is private; it is used ONLY
904 : * by the DEBUG-mode checking macros in this class and its friends;
905 : * other code is not allowed to ask a logical point for its writing mode,
906 : * as this info will simply not be available in non-DEBUG builds.
907 : *
908 : * Also, in non-DEBUG builds, CHECK_WRITING_MODE does nothing, and the
909 : * WritingMode parameter to logical methods will generally be optimized
910 : * away altogether.
911 : */
912 : #ifdef DEBUG
913 420 : WritingMode GetWritingMode() const { return mWritingMode; }
914 : #else
915 : WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
916 : #endif
917 :
918 : // We don't allow construction of a LogicalPoint with no writing mode.
919 : LogicalPoint() = delete;
920 :
921 : // Accessors that don't take or check a WritingMode value.
922 : // These are for internal use only; they are called by methods that have
923 : // themselves already checked the WritingMode passed by the caller.
924 100 : nscoord I() const // inline-axis
925 : {
926 100 : return mPoint.x;
927 : }
928 100 : nscoord B() const // block-axis
929 : {
930 100 : return mPoint.y;
931 : }
932 :
933 209 : nscoord& I() // inline-axis
934 : {
935 209 : return mPoint.x;
936 : }
937 209 : nscoord& B() // block-axis
938 : {
939 209 : return mPoint.y;
940 : }
941 :
942 : #ifdef DEBUG
943 : WritingMode mWritingMode;
944 : #endif
945 :
946 : // We use an nsPoint to hold the coordinates, but reinterpret its .x and .y
947 : // fields as the inline and block directions. Hence, this is not exposed
948 : // directly, but only through accessors that will map them according to the
949 : // writing mode.
950 : nsPoint mPoint;
951 : };
952 :
953 : /**
954 : * Flow-relative size
955 : */
956 : class LogicalSize {
957 : public:
958 1634 : explicit LogicalSize(WritingMode aWritingMode)
959 1634 : :
960 : #ifdef DEBUG
961 : mWritingMode(aWritingMode),
962 : #endif
963 1634 : mSize(0, 0)
964 1634 : { }
965 :
966 5928 : LogicalSize(WritingMode aWritingMode, nscoord aISize, nscoord aBSize)
967 5928 : :
968 : #ifdef DEBUG
969 : mWritingMode(aWritingMode),
970 : #endif
971 5928 : mSize(aISize, aBSize)
972 5928 : { }
973 :
974 2089 : LogicalSize(WritingMode aWritingMode, const nsSize& aPhysicalSize)
975 : #ifdef DEBUG
976 2089 : : mWritingMode(aWritingMode)
977 : #endif
978 : {
979 2089 : if (aWritingMode.IsVertical()) {
980 0 : ISize() = aPhysicalSize.height;
981 0 : BSize() = aPhysicalSize.width;
982 : } else {
983 2089 : ISize() = aPhysicalSize.width;
984 2089 : BSize() = aPhysicalSize.height;
985 : }
986 2089 : }
987 :
988 0 : void SizeTo(WritingMode aWritingMode, nscoord aISize, nscoord aBSize)
989 : {
990 0 : CHECK_WRITING_MODE(aWritingMode);
991 0 : mSize.SizeTo(aISize, aBSize);
992 0 : }
993 :
994 : /**
995 : * Dimensions in logical and physical terms
996 : */
997 4042 : nscoord ISize(WritingMode aWritingMode) const // inline-size
998 : {
999 4042 : CHECK_WRITING_MODE(aWritingMode);
1000 4042 : return mSize.width;
1001 : }
1002 2188 : nscoord BSize(WritingMode aWritingMode) const // block-size
1003 : {
1004 2188 : CHECK_WRITING_MODE(aWritingMode);
1005 2188 : return mSize.height;
1006 : }
1007 :
1008 0 : nscoord Width(WritingMode aWritingMode) const
1009 : {
1010 0 : CHECK_WRITING_MODE(aWritingMode);
1011 0 : return aWritingMode.IsVertical() ? BSize() : ISize();
1012 : }
1013 37 : nscoord Height(WritingMode aWritingMode) const
1014 : {
1015 37 : CHECK_WRITING_MODE(aWritingMode);
1016 37 : return aWritingMode.IsVertical() ? ISize() : BSize();
1017 : }
1018 :
1019 : /**
1020 : * Writable references to the logical dimensions
1021 : */
1022 7057 : nscoord& ISize(WritingMode aWritingMode) // inline-size
1023 : {
1024 7057 : CHECK_WRITING_MODE(aWritingMode);
1025 7057 : return mSize.width;
1026 : }
1027 5502 : nscoord& BSize(WritingMode aWritingMode) // block-size
1028 : {
1029 5502 : CHECK_WRITING_MODE(aWritingMode);
1030 5502 : return mSize.height;
1031 : }
1032 :
1033 : /**
1034 : * Return an nsSize containing our physical dimensions
1035 : */
1036 606 : nsSize GetPhysicalSize(WritingMode aWritingMode) const
1037 : {
1038 606 : CHECK_WRITING_MODE(aWritingMode);
1039 606 : return aWritingMode.IsVertical() ?
1040 606 : nsSize(BSize(), ISize()) : nsSize(ISize(), BSize());
1041 : }
1042 :
1043 : /**
1044 : * Return a LogicalSize representing this size in a different writing mode
1045 : */
1046 2577 : LogicalSize ConvertTo(WritingMode aToMode, WritingMode aFromMode) const
1047 : {
1048 : #ifdef DEBUG
1049 : // In DEBUG builds make sure to return a LogicalSize with the
1050 : // expected writing mode
1051 2577 : CHECK_WRITING_MODE(aFromMode);
1052 2577 : return aToMode == aFromMode ?
1053 2577 : *this : LogicalSize(aToMode, GetPhysicalSize(aFromMode));
1054 : #else
1055 : // optimization for non-DEBUG builds where LogicalSize doesn't store
1056 : // the writing mode
1057 : return (aToMode == aFromMode || !aToMode.IsOrthogonalTo(aFromMode))
1058 : ? *this : LogicalSize(aToMode, BSize(), ISize());
1059 : #endif
1060 : }
1061 :
1062 : /**
1063 : * Test if a size is (0, 0).
1064 : */
1065 0 : bool IsAllZero() const
1066 : {
1067 0 : return ISize() == 0 && BSize() == 0;
1068 : }
1069 :
1070 : /**
1071 : * Various binary operators on LogicalSize. These are valid ONLY for operands
1072 : * that share the same writing mode.
1073 : */
1074 397 : bool operator==(const LogicalSize& aOther) const
1075 : {
1076 397 : CHECK_WRITING_MODE(aOther.GetWritingMode());
1077 397 : return mSize == aOther.mSize;
1078 : }
1079 :
1080 0 : bool operator!=(const LogicalSize& aOther) const
1081 : {
1082 0 : CHECK_WRITING_MODE(aOther.GetWritingMode());
1083 0 : return mSize != aOther.mSize;
1084 : }
1085 :
1086 177 : LogicalSize operator+(const LogicalSize& aOther) const
1087 : {
1088 177 : CHECK_WRITING_MODE(aOther.GetWritingMode());
1089 354 : return LogicalSize(GetWritingMode(), ISize() + aOther.ISize(),
1090 531 : BSize() + aOther.BSize());
1091 : }
1092 0 : LogicalSize& operator+=(const LogicalSize& aOther)
1093 : {
1094 0 : CHECK_WRITING_MODE(aOther.GetWritingMode());
1095 0 : ISize() += aOther.ISize();
1096 0 : BSize() += aOther.BSize();
1097 0 : return *this;
1098 : }
1099 :
1100 511 : LogicalSize operator-(const LogicalSize& aOther) const
1101 : {
1102 511 : CHECK_WRITING_MODE(aOther.GetWritingMode());
1103 1022 : return LogicalSize(GetWritingMode(), ISize() - aOther.ISize(),
1104 1533 : BSize() - aOther.BSize());
1105 : }
1106 0 : LogicalSize& operator-=(const LogicalSize& aOther)
1107 : {
1108 0 : CHECK_WRITING_MODE(aOther.GetWritingMode());
1109 0 : ISize() -= aOther.ISize();
1110 0 : BSize() -= aOther.BSize();
1111 0 : return *this;
1112 : }
1113 :
1114 : private:
1115 : friend class LogicalRect;
1116 :
1117 : LogicalSize() = delete;
1118 :
1119 : #ifdef DEBUG
1120 24946 : WritingMode GetWritingMode() const { return mWritingMode; }
1121 : #else
1122 : WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
1123 : #endif
1124 :
1125 1982 : nscoord ISize() const // inline-size
1126 : {
1127 1982 : return mSize.width;
1128 : }
1129 2019 : nscoord BSize() const // block-size
1130 : {
1131 2019 : return mSize.height;
1132 : }
1133 :
1134 2089 : nscoord& ISize() // inline-size
1135 : {
1136 2089 : return mSize.width;
1137 : }
1138 2089 : nscoord& BSize() // block-size
1139 : {
1140 2089 : return mSize.height;
1141 : }
1142 :
1143 : #ifdef DEBUG
1144 : WritingMode mWritingMode;
1145 : #endif
1146 : nsSize mSize;
1147 : };
1148 :
1149 : /**
1150 : * Flow-relative margin
1151 : */
1152 1291 : class LogicalMargin {
1153 : public:
1154 450 : explicit LogicalMargin(WritingMode aWritingMode)
1155 450 : :
1156 : #ifdef DEBUG
1157 : mWritingMode(aWritingMode),
1158 : #endif
1159 450 : mMargin(0, 0, 0, 0)
1160 450 : { }
1161 :
1162 77 : LogicalMargin(WritingMode aWritingMode,
1163 : nscoord aBStart, nscoord aIEnd,
1164 : nscoord aBEnd, nscoord aIStart)
1165 77 : :
1166 : #ifdef DEBUG
1167 : mWritingMode(aWritingMode),
1168 : #endif
1169 77 : mMargin(aBStart, aIEnd, aBEnd, aIStart)
1170 77 : { }
1171 :
1172 6035 : LogicalMargin(WritingMode aWritingMode, const nsMargin& aPhysicalMargin)
1173 : #ifdef DEBUG
1174 6035 : : mWritingMode(aWritingMode)
1175 : #endif
1176 : {
1177 6035 : if (aWritingMode.IsVertical()) {
1178 0 : if (aWritingMode.IsVerticalLR()) {
1179 0 : mMargin.top = aPhysicalMargin.left;
1180 0 : mMargin.bottom = aPhysicalMargin.right;
1181 : } else {
1182 0 : mMargin.top = aPhysicalMargin.right;
1183 0 : mMargin.bottom = aPhysicalMargin.left;
1184 : }
1185 0 : if (aWritingMode.IsInlineReversed()) {
1186 0 : mMargin.left = aPhysicalMargin.bottom;
1187 0 : mMargin.right = aPhysicalMargin.top;
1188 : } else {
1189 0 : mMargin.left = aPhysicalMargin.top;
1190 0 : mMargin.right = aPhysicalMargin.bottom;
1191 : }
1192 : } else {
1193 6035 : mMargin.top = aPhysicalMargin.top;
1194 6035 : mMargin.bottom = aPhysicalMargin.bottom;
1195 6035 : if (aWritingMode.IsInlineReversed()) {
1196 0 : mMargin.left = aPhysicalMargin.right;
1197 0 : mMargin.right = aPhysicalMargin.left;
1198 : } else {
1199 6035 : mMargin.left = aPhysicalMargin.left;
1200 6035 : mMargin.right = aPhysicalMargin.right;
1201 : }
1202 : }
1203 6035 : }
1204 :
1205 266 : nscoord IStart(WritingMode aWritingMode) const // inline-start margin
1206 : {
1207 266 : CHECK_WRITING_MODE(aWritingMode);
1208 266 : return mMargin.left;
1209 : }
1210 162 : nscoord IEnd(WritingMode aWritingMode) const // inline-end margin
1211 : {
1212 162 : CHECK_WRITING_MODE(aWritingMode);
1213 162 : return mMargin.right;
1214 : }
1215 406 : nscoord BStart(WritingMode aWritingMode) const // block-start margin
1216 : {
1217 406 : CHECK_WRITING_MODE(aWritingMode);
1218 406 : return mMargin.top;
1219 : }
1220 324 : nscoord BEnd(WritingMode aWritingMode) const // block-end margin
1221 : {
1222 324 : CHECK_WRITING_MODE(aWritingMode);
1223 324 : return mMargin.bottom;
1224 : }
1225 :
1226 863 : nscoord& IStart(WritingMode aWritingMode) // inline-start margin
1227 : {
1228 863 : CHECK_WRITING_MODE(aWritingMode);
1229 863 : return mMargin.left;
1230 : }
1231 336 : nscoord& IEnd(WritingMode aWritingMode) // inline-end margin
1232 : {
1233 336 : CHECK_WRITING_MODE(aWritingMode);
1234 336 : return mMargin.right;
1235 : }
1236 798 : nscoord& BStart(WritingMode aWritingMode) // block-start margin
1237 : {
1238 798 : CHECK_WRITING_MODE(aWritingMode);
1239 798 : return mMargin.top;
1240 : }
1241 346 : nscoord& BEnd(WritingMode aWritingMode) // block-end margin
1242 : {
1243 346 : CHECK_WRITING_MODE(aWritingMode);
1244 346 : return mMargin.bottom;
1245 : }
1246 :
1247 2399 : nscoord IStartEnd(WritingMode aWritingMode) const // inline margins
1248 : {
1249 2399 : CHECK_WRITING_MODE(aWritingMode);
1250 2399 : return mMargin.LeftRight();
1251 : }
1252 579 : nscoord BStartEnd(WritingMode aWritingMode) const // block margins
1253 : {
1254 579 : CHECK_WRITING_MODE(aWritingMode);
1255 579 : return mMargin.TopBottom();
1256 : }
1257 :
1258 : /*
1259 : * Return margin values for line-relative sides, as defined in
1260 : * http://www.w3.org/TR/css-writing-modes-3/#line-directions:
1261 : *
1262 : * line-left
1263 : * Nominally the side from which LTR text would start.
1264 : * line-right
1265 : * Nominally the side from which RTL text would start. (Opposite of
1266 : * line-left.)
1267 : */
1268 0 : nscoord LineLeft(WritingMode aWritingMode) const
1269 : {
1270 : // We don't need to CHECK_WRITING_MODE here because the IStart or IEnd
1271 : // accessor that we call will do it.
1272 0 : return aWritingMode.IsBidiLTR()
1273 0 : ? IStart(aWritingMode) : IEnd(aWritingMode);
1274 : }
1275 0 : nscoord LineRight(WritingMode aWritingMode) const
1276 : {
1277 0 : return aWritingMode.IsBidiLTR()
1278 0 : ? IEnd(aWritingMode) : IStart(aWritingMode);
1279 : }
1280 :
1281 : /**
1282 : * Return a LogicalSize representing the total size of the inline-
1283 : * and block-dimension margins.
1284 : */
1285 1967 : LogicalSize Size(WritingMode aWritingMode) const
1286 : {
1287 1967 : CHECK_WRITING_MODE(aWritingMode);
1288 1967 : return LogicalSize(aWritingMode, IStartEnd(), BStartEnd());
1289 : }
1290 :
1291 : /**
1292 : * Accessors for physical margins, using our writing mode to convert from
1293 : * logical values.
1294 : */
1295 0 : nscoord Top(WritingMode aWritingMode) const
1296 : {
1297 0 : CHECK_WRITING_MODE(aWritingMode);
1298 0 : return aWritingMode.IsVertical() ?
1299 0 : (aWritingMode.IsInlineReversed() ? IEnd() : IStart()) : BStart();
1300 : }
1301 :
1302 : nscoord Bottom(WritingMode aWritingMode) const
1303 : {
1304 : CHECK_WRITING_MODE(aWritingMode);
1305 : return aWritingMode.IsVertical() ?
1306 : (aWritingMode.IsInlineReversed() ? IStart() : IEnd()) : BEnd();
1307 : }
1308 :
1309 0 : nscoord Left(WritingMode aWritingMode) const
1310 : {
1311 0 : CHECK_WRITING_MODE(aWritingMode);
1312 0 : return aWritingMode.IsVertical() ?
1313 0 : (aWritingMode.IsVerticalLR() ? BStart() : BEnd()) :
1314 0 : (aWritingMode.IsInlineReversed() ? IEnd() : IStart());
1315 : }
1316 :
1317 : nscoord Right(WritingMode aWritingMode) const
1318 : {
1319 : CHECK_WRITING_MODE(aWritingMode);
1320 : return aWritingMode.IsVertical() ?
1321 : (aWritingMode.IsVerticalLR() ? BEnd() : BStart()) :
1322 : (aWritingMode.IsInlineReversed() ? IStart() : IEnd());
1323 : }
1324 :
1325 162 : nscoord LeftRight(WritingMode aWritingMode) const
1326 : {
1327 162 : CHECK_WRITING_MODE(aWritingMode);
1328 162 : return aWritingMode.IsVertical() ? BStartEnd() : IStartEnd();
1329 : }
1330 :
1331 162 : nscoord TopBottom(WritingMode aWritingMode) const
1332 : {
1333 162 : CHECK_WRITING_MODE(aWritingMode);
1334 162 : return aWritingMode.IsVertical() ? IStartEnd() : BStartEnd();
1335 : }
1336 :
1337 0 : void SizeTo(WritingMode aWritingMode,
1338 : nscoord aBStart, nscoord aIEnd, nscoord aBEnd, nscoord aIStart)
1339 : {
1340 0 : CHECK_WRITING_MODE(aWritingMode);
1341 0 : mMargin.SizeTo(aBStart, aIEnd, aBEnd, aIStart);
1342 0 : }
1343 :
1344 : /**
1345 : * Return an nsMargin containing our physical coordinates
1346 : */
1347 449 : nsMargin GetPhysicalMargin(WritingMode aWritingMode) const
1348 : {
1349 449 : CHECK_WRITING_MODE(aWritingMode);
1350 449 : return aWritingMode.IsVertical()
1351 0 : ? (aWritingMode.IsVerticalLR()
1352 0 : ? (aWritingMode.IsInlineReversed()
1353 : ? nsMargin(IEnd(), BEnd(), IStart(), BStart())
1354 : : nsMargin(IStart(), BEnd(), IEnd(), BStart()))
1355 0 : : (aWritingMode.IsInlineReversed()
1356 : ? nsMargin(IEnd(), BStart(), IStart(), BEnd())
1357 : : nsMargin(IStart(), BStart(), IEnd(), BEnd())))
1358 449 : : (aWritingMode.IsInlineReversed()
1359 : ? nsMargin(BStart(), IStart(), BEnd(), IEnd())
1360 898 : : nsMargin(BStart(), IEnd(), BEnd(), IStart()));
1361 : }
1362 :
1363 : /**
1364 : * Return a LogicalMargin representing this margin in a different
1365 : * writing mode
1366 : */
1367 1291 : LogicalMargin ConvertTo(WritingMode aToMode, WritingMode aFromMode) const
1368 : {
1369 1291 : CHECK_WRITING_MODE(aFromMode);
1370 1291 : return aToMode == aFromMode ?
1371 1291 : *this : LogicalMargin(aToMode, GetPhysicalMargin(aFromMode));
1372 : }
1373 :
1374 162 : void ApplySkipSides(LogicalSides aSkipSides)
1375 : {
1376 162 : if (aSkipSides.BStart()) {
1377 0 : BStart() = 0;
1378 : }
1379 162 : if (aSkipSides.BEnd()) {
1380 0 : BEnd() = 0;
1381 : }
1382 162 : if (aSkipSides.IStart()) {
1383 0 : IStart() = 0;
1384 : }
1385 162 : if (aSkipSides.IEnd()) {
1386 0 : IEnd() = 0;
1387 : }
1388 162 : }
1389 :
1390 0 : bool IsAllZero() const
1391 : {
1392 0 : return (mMargin.left == 0 && mMargin.top == 0 &&
1393 0 : mMargin.right == 0 && mMargin.bottom == 0);
1394 : }
1395 :
1396 : LogicalMargin operator+(const LogicalMargin& aMargin) const {
1397 : CHECK_WRITING_MODE(aMargin.GetWritingMode());
1398 : return LogicalMargin(GetWritingMode(),
1399 : BStart() + aMargin.BStart(),
1400 : IEnd() + aMargin.IEnd(),
1401 : BEnd() + aMargin.BEnd(),
1402 : IStart() + aMargin.IStart());
1403 : }
1404 :
1405 0 : LogicalMargin operator+=(const LogicalMargin& aMargin)
1406 : {
1407 0 : CHECK_WRITING_MODE(aMargin.GetWritingMode());
1408 0 : mMargin += aMargin.mMargin;
1409 0 : return *this;
1410 : }
1411 :
1412 77 : LogicalMargin operator-(const LogicalMargin& aMargin) const {
1413 77 : CHECK_WRITING_MODE(aMargin.GetWritingMode());
1414 : return LogicalMargin(GetWritingMode(),
1415 77 : BStart() - aMargin.BStart(),
1416 77 : IEnd() - aMargin.IEnd(),
1417 77 : BEnd() - aMargin.BEnd(),
1418 308 : IStart() - aMargin.IStart());
1419 : }
1420 :
1421 : private:
1422 : friend class LogicalRect;
1423 :
1424 : LogicalMargin() = delete;
1425 :
1426 : #ifdef DEBUG
1427 10765 : WritingMode GetWritingMode() const { return mWritingMode; }
1428 : #else
1429 : WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
1430 : #endif
1431 :
1432 603 : nscoord IStart() const // inline-start margin
1433 : {
1434 603 : return mMargin.left;
1435 : }
1436 603 : nscoord IEnd() const // inline-end margin
1437 : {
1438 603 : return mMargin.right;
1439 : }
1440 603 : nscoord BStart() const // block-start margin
1441 : {
1442 603 : return mMargin.top;
1443 : }
1444 603 : nscoord BEnd() const // block-end margin
1445 : {
1446 603 : return mMargin.bottom;
1447 : }
1448 :
1449 0 : nscoord& IStart() // inline-start margin
1450 : {
1451 0 : return mMargin.left;
1452 : }
1453 0 : nscoord& IEnd() // inline-end margin
1454 : {
1455 0 : return mMargin.right;
1456 : }
1457 0 : nscoord& BStart() // block-start margin
1458 : {
1459 0 : return mMargin.top;
1460 : }
1461 0 : nscoord& BEnd() // block-end margin
1462 : {
1463 0 : return mMargin.bottom;
1464 : }
1465 :
1466 2129 : nscoord IStartEnd() const // inline margins
1467 : {
1468 2129 : return mMargin.LeftRight();
1469 : }
1470 2129 : nscoord BStartEnd() const // block margins
1471 : {
1472 2129 : return mMargin.TopBottom();
1473 : }
1474 :
1475 : #ifdef DEBUG
1476 : WritingMode mWritingMode;
1477 : #endif
1478 : nsMargin mMargin;
1479 : };
1480 :
1481 : /**
1482 : * Flow-relative rectangle
1483 : */
1484 1849 : class LogicalRect {
1485 : public:
1486 365 : explicit LogicalRect(WritingMode aWritingMode)
1487 365 : :
1488 : #ifdef DEBUG
1489 : mWritingMode(aWritingMode),
1490 : #endif
1491 365 : mRect(0, 0, 0, 0)
1492 365 : { }
1493 :
1494 482 : LogicalRect(WritingMode aWritingMode,
1495 : nscoord aIStart, nscoord aBStart,
1496 : nscoord aISize, nscoord aBSize)
1497 482 : :
1498 : #ifdef DEBUG
1499 : mWritingMode(aWritingMode),
1500 : #endif
1501 482 : mRect(aIStart, aBStart, aISize, aBSize)
1502 482 : { }
1503 :
1504 79 : LogicalRect(WritingMode aWritingMode,
1505 : const LogicalPoint& aOrigin,
1506 : const LogicalSize& aSize)
1507 79 : :
1508 : #ifdef DEBUG
1509 : mWritingMode(aWritingMode),
1510 : #endif
1511 79 : mRect(aOrigin.mPoint, aSize.mSize)
1512 : {
1513 79 : CHECK_WRITING_MODE(aOrigin.GetWritingMode());
1514 79 : CHECK_WRITING_MODE(aSize.GetWritingMode());
1515 79 : }
1516 :
1517 24 : LogicalRect(WritingMode aWritingMode,
1518 : const nsRect& aRect,
1519 : const nsSize& aContainerSize)
1520 : #ifdef DEBUG
1521 24 : : mWritingMode(aWritingMode)
1522 : #endif
1523 : {
1524 24 : if (aWritingMode.IsVertical()) {
1525 0 : mRect.y = aWritingMode.IsVerticalLR()
1526 0 : ? aRect.x : aContainerSize.width - aRect.XMost();
1527 0 : mRect.x = aWritingMode.IsInlineReversed()
1528 0 : ? aContainerSize.height - aRect.YMost() : aRect.y;
1529 0 : mRect.height = aRect.width;
1530 0 : mRect.width = aRect.height;
1531 : } else {
1532 48 : mRect.x = aWritingMode.IsInlineReversed()
1533 24 : ? aContainerSize.width - aRect.XMost() : aRect.x;
1534 24 : mRect.y = aRect.y;
1535 24 : mRect.width = aRect.width;
1536 24 : mRect.height = aRect.height;
1537 : }
1538 24 : }
1539 :
1540 : /**
1541 : * Inline- and block-dimension geometry.
1542 : */
1543 309 : nscoord IStart(WritingMode aWritingMode) const // inline-start edge
1544 : {
1545 309 : CHECK_WRITING_MODE(aWritingMode);
1546 309 : return mRect.X();
1547 : }
1548 334 : nscoord IEnd(WritingMode aWritingMode) const // inline-end edge
1549 : {
1550 334 : CHECK_WRITING_MODE(aWritingMode);
1551 334 : return mRect.XMost();
1552 : }
1553 223 : nscoord ISize(WritingMode aWritingMode) const // inline-size
1554 : {
1555 223 : CHECK_WRITING_MODE(aWritingMode);
1556 223 : return mRect.Width();
1557 : }
1558 :
1559 454 : nscoord BStart(WritingMode aWritingMode) const // block-start edge
1560 : {
1561 454 : CHECK_WRITING_MODE(aWritingMode);
1562 454 : return mRect.Y();
1563 : }
1564 451 : nscoord BEnd(WritingMode aWritingMode) const // block-end edge
1565 : {
1566 451 : CHECK_WRITING_MODE(aWritingMode);
1567 451 : return mRect.YMost();
1568 : }
1569 352 : nscoord BSize(WritingMode aWritingMode) const // block-size
1570 : {
1571 352 : CHECK_WRITING_MODE(aWritingMode);
1572 352 : return mRect.Height();
1573 : }
1574 :
1575 : /**
1576 : * Writable (reference) accessors are only available for the basic logical
1577 : * fields (Start and Size), not derivatives like End.
1578 : */
1579 678 : nscoord& IStart(WritingMode aWritingMode) // inline-start edge
1580 : {
1581 678 : CHECK_WRITING_MODE(aWritingMode);
1582 678 : return mRect.x;
1583 : }
1584 1145 : nscoord& ISize(WritingMode aWritingMode) // inline-size
1585 : {
1586 1145 : CHECK_WRITING_MODE(aWritingMode);
1587 1145 : return mRect.width;
1588 : }
1589 548 : nscoord& BStart(WritingMode aWritingMode) // block-start edge
1590 : {
1591 548 : CHECK_WRITING_MODE(aWritingMode);
1592 548 : return mRect.y;
1593 : }
1594 376 : nscoord& BSize(WritingMode aWritingMode) // block-size
1595 : {
1596 376 : CHECK_WRITING_MODE(aWritingMode);
1597 376 : return mRect.height;
1598 : }
1599 :
1600 : /**
1601 : * Accessors for line-relative coordinates
1602 : */
1603 85 : nscoord LineLeft(WritingMode aWritingMode,
1604 : const nsSize& aContainerSize) const
1605 : {
1606 85 : CHECK_WRITING_MODE(aWritingMode);
1607 85 : if (aWritingMode.IsBidiLTR()) {
1608 85 : return IStart();
1609 : }
1610 : nscoord containerISize =
1611 0 : aWritingMode.IsVertical() ? aContainerSize.height : aContainerSize.width;
1612 0 : return containerISize - IEnd();
1613 : }
1614 0 : nscoord LineRight(WritingMode aWritingMode,
1615 : const nsSize& aContainerSize) const
1616 : {
1617 0 : CHECK_WRITING_MODE(aWritingMode);
1618 0 : if (aWritingMode.IsBidiLTR()) {
1619 0 : return IEnd();
1620 : }
1621 : nscoord containerISize =
1622 0 : aWritingMode.IsVertical() ? aContainerSize.height : aContainerSize.width;
1623 0 : return containerISize - IStart();
1624 : }
1625 :
1626 : /**
1627 : * Physical coordinates of the rect.
1628 : */
1629 : nscoord X(WritingMode aWritingMode, nscoord aContainerWidth) const
1630 : {
1631 : CHECK_WRITING_MODE(aWritingMode);
1632 : if (aWritingMode.IsVertical()) {
1633 : return aWritingMode.IsVerticalLR() ?
1634 : mRect.Y() : aContainerWidth - mRect.YMost();
1635 : } else {
1636 : return aWritingMode.IsInlineReversed() ?
1637 : aContainerWidth - mRect.XMost() : mRect.X();
1638 : }
1639 : }
1640 :
1641 : nscoord Y(WritingMode aWritingMode, nscoord aContainerHeight) const
1642 : {
1643 : CHECK_WRITING_MODE(aWritingMode);
1644 : if (aWritingMode.IsVertical()) {
1645 : return aWritingMode.IsInlineReversed() ? aContainerHeight - mRect.XMost()
1646 : : mRect.X();
1647 : } else {
1648 : return mRect.Y();
1649 : }
1650 : }
1651 :
1652 0 : nscoord Width(WritingMode aWritingMode) const
1653 : {
1654 0 : CHECK_WRITING_MODE(aWritingMode);
1655 0 : return aWritingMode.IsVertical() ? mRect.Height() : mRect.Width();
1656 : }
1657 :
1658 0 : nscoord Height(WritingMode aWritingMode) const
1659 : {
1660 0 : CHECK_WRITING_MODE(aWritingMode);
1661 0 : return aWritingMode.IsVertical() ? mRect.Width() : mRect.Height();
1662 : }
1663 :
1664 : nscoord XMost(WritingMode aWritingMode, nscoord aContainerWidth) const
1665 : {
1666 : CHECK_WRITING_MODE(aWritingMode);
1667 : if (aWritingMode.IsVertical()) {
1668 : return aWritingMode.IsVerticalLR() ?
1669 : mRect.YMost() : aContainerWidth - mRect.Y();
1670 : } else {
1671 : return aWritingMode.IsInlineReversed() ?
1672 : aContainerWidth - mRect.X() : mRect.XMost();
1673 : }
1674 : }
1675 :
1676 : nscoord YMost(WritingMode aWritingMode, nscoord aContainerHeight) const
1677 : {
1678 : CHECK_WRITING_MODE(aWritingMode);
1679 : if (aWritingMode.IsVertical()) {
1680 : return aWritingMode.IsInlineReversed() ? aContainerHeight - mRect.x
1681 : : mRect.XMost();
1682 : } else {
1683 : return mRect.YMost();
1684 : }
1685 : }
1686 :
1687 : bool IsEmpty() const
1688 : {
1689 : return mRect.IsEmpty();
1690 : }
1691 :
1692 323 : bool IsAllZero() const
1693 : {
1694 689 : return (mRect.x == 0 && mRect.y == 0 &&
1695 570 : mRect.width == 0 && mRect.height == 0);
1696 : }
1697 :
1698 0 : bool IsZeroSize() const
1699 : {
1700 0 : return (mRect.width == 0 && mRect.height == 0);
1701 : }
1702 :
1703 0 : void SetEmpty() { mRect.SetEmpty(); }
1704 :
1705 0 : bool IsEqualEdges(const LogicalRect aOther) const
1706 : {
1707 0 : CHECK_WRITING_MODE(aOther.GetWritingMode());
1708 0 : return mRect.IsEqualEdges(aOther.mRect);
1709 : }
1710 :
1711 0 : LogicalPoint Origin(WritingMode aWritingMode) const
1712 : {
1713 0 : CHECK_WRITING_MODE(aWritingMode);
1714 0 : return LogicalPoint(aWritingMode, IStart(), BStart());
1715 : }
1716 0 : void SetOrigin(WritingMode aWritingMode, const LogicalPoint& aPoint)
1717 : {
1718 0 : IStart(aWritingMode) = aPoint.I(aWritingMode);
1719 0 : BStart(aWritingMode) = aPoint.B(aWritingMode);
1720 0 : }
1721 :
1722 20 : LogicalSize Size(WritingMode aWritingMode) const
1723 : {
1724 20 : CHECK_WRITING_MODE(aWritingMode);
1725 20 : return LogicalSize(aWritingMode, ISize(), BSize());
1726 : }
1727 :
1728 : LogicalRect operator+(const LogicalPoint& aPoint) const
1729 : {
1730 : CHECK_WRITING_MODE(aPoint.GetWritingMode());
1731 : return LogicalRect(GetWritingMode(),
1732 : IStart() + aPoint.I(), BStart() + aPoint.B(),
1733 : ISize(), BSize());
1734 : }
1735 :
1736 0 : LogicalRect& operator+=(const LogicalPoint& aPoint)
1737 : {
1738 0 : CHECK_WRITING_MODE(aPoint.GetWritingMode());
1739 0 : mRect += aPoint.mPoint;
1740 0 : return *this;
1741 : }
1742 :
1743 0 : LogicalRect operator-(const LogicalPoint& aPoint) const
1744 : {
1745 0 : CHECK_WRITING_MODE(aPoint.GetWritingMode());
1746 : return LogicalRect(GetWritingMode(),
1747 0 : IStart() - aPoint.I(), BStart() - aPoint.B(),
1748 0 : ISize(), BSize());
1749 : }
1750 :
1751 : LogicalRect& operator-=(const LogicalPoint& aPoint)
1752 : {
1753 : CHECK_WRITING_MODE(aPoint.GetWritingMode());
1754 : mRect -= aPoint.mPoint;
1755 : return *this;
1756 : }
1757 :
1758 0 : void MoveBy(WritingMode aWritingMode, const LogicalPoint& aDelta)
1759 : {
1760 0 : CHECK_WRITING_MODE(aWritingMode);
1761 0 : CHECK_WRITING_MODE(aDelta.GetWritingMode());
1762 0 : IStart() += aDelta.I();
1763 0 : BStart() += aDelta.B();
1764 0 : }
1765 :
1766 : void Inflate(nscoord aD) { mRect.Inflate(aD); }
1767 : void Inflate(nscoord aDI, nscoord aDB) { mRect.Inflate(aDI, aDB); }
1768 0 : void Inflate(WritingMode aWritingMode, const LogicalMargin& aMargin)
1769 : {
1770 0 : CHECK_WRITING_MODE(aWritingMode);
1771 0 : CHECK_WRITING_MODE(aMargin.GetWritingMode());
1772 0 : mRect.Inflate(aMargin.mMargin);
1773 0 : }
1774 :
1775 : void Deflate(nscoord aD) { mRect.Deflate(aD); }
1776 : void Deflate(nscoord aDI, nscoord aDB) { mRect.Deflate(aDI, aDB); }
1777 24 : void Deflate(WritingMode aWritingMode, const LogicalMargin& aMargin)
1778 : {
1779 24 : CHECK_WRITING_MODE(aWritingMode);
1780 24 : CHECK_WRITING_MODE(aMargin.GetWritingMode());
1781 24 : mRect.Deflate(aMargin.mMargin);
1782 24 : }
1783 :
1784 : /**
1785 : * Return an nsRect containing our physical coordinates within the given
1786 : * container size.
1787 : */
1788 681 : nsRect GetPhysicalRect(WritingMode aWritingMode,
1789 : const nsSize& aContainerSize) const
1790 : {
1791 681 : CHECK_WRITING_MODE(aWritingMode);
1792 681 : if (aWritingMode.IsVertical()) {
1793 0 : return nsRect(aWritingMode.IsVerticalLR()
1794 0 : ? BStart() : aContainerSize.width - BEnd(),
1795 0 : aWritingMode.IsInlineReversed()
1796 0 : ? aContainerSize.height - IEnd() : IStart(),
1797 0 : BSize(), ISize());
1798 : } else {
1799 681 : return nsRect(aWritingMode.IsInlineReversed()
1800 0 : ? aContainerSize.width - IEnd() : IStart(),
1801 1362 : BStart(), ISize(), BSize());
1802 : }
1803 : }
1804 :
1805 : /**
1806 : * Return a LogicalRect representing this rect in a different writing mode
1807 : */
1808 75 : LogicalRect ConvertTo(WritingMode aToMode, WritingMode aFromMode,
1809 : const nsSize& aContainerSize) const
1810 : {
1811 75 : CHECK_WRITING_MODE(aFromMode);
1812 75 : return aToMode == aFromMode ?
1813 75 : *this : LogicalRect(aToMode, GetPhysicalRect(aFromMode, aContainerSize),
1814 225 : aContainerSize);
1815 : }
1816 :
1817 : /**
1818 : * Set *this to be the rectangle containing the intersection of aRect1
1819 : * and aRect2, return whether the intersection is non-empty.
1820 : */
1821 0 : bool IntersectRect(const LogicalRect& aRect1, const LogicalRect& aRect2)
1822 : {
1823 0 : CHECK_WRITING_MODE(aRect1.mWritingMode);
1824 0 : CHECK_WRITING_MODE(aRect2.mWritingMode);
1825 0 : return mRect.IntersectRect(aRect1.mRect, aRect2.mRect);
1826 : }
1827 :
1828 : private:
1829 : LogicalRect() = delete;
1830 :
1831 : #ifdef DEBUG
1832 5937 : WritingMode GetWritingMode() const { return mWritingMode; }
1833 : #else
1834 : WritingMode GetWritingMode() const { return WritingMode::Unknown(); }
1835 : #endif
1836 :
1837 766 : nscoord IStart() const // inline-start edge
1838 : {
1839 766 : return mRect.X();
1840 : }
1841 0 : nscoord IEnd() const // inline-end edge
1842 : {
1843 0 : return mRect.XMost();
1844 : }
1845 701 : nscoord ISize() const // inline-size
1846 : {
1847 701 : return mRect.Width();
1848 : }
1849 :
1850 681 : nscoord BStart() const // block-start edge
1851 : {
1852 681 : return mRect.Y();
1853 : }
1854 0 : nscoord BEnd() const // block-end edge
1855 : {
1856 0 : return mRect.YMost();
1857 : }
1858 701 : nscoord BSize() const // block-size
1859 : {
1860 701 : return mRect.Height();
1861 : }
1862 :
1863 0 : nscoord& IStart() // inline-start edge
1864 : {
1865 0 : return mRect.x;
1866 : }
1867 : nscoord& ISize() // inline-size
1868 : {
1869 : return mRect.width;
1870 : }
1871 0 : nscoord& BStart() // block-start edge
1872 : {
1873 0 : return mRect.y;
1874 : }
1875 : nscoord& BSize() // block-size
1876 : {
1877 : return mRect.height;
1878 : }
1879 :
1880 : #ifdef DEBUG
1881 : WritingMode mWritingMode;
1882 : #endif
1883 : nsRect mRect;
1884 : };
1885 :
1886 : } // namespace mozilla
1887 :
1888 : // Definitions of inline methods for nsStyleSides, declared in nsStyleCoord.h
1889 : // but not defined there because they need WritingMode.
1890 1307 : inline nsStyleUnit nsStyleSides::GetUnit(mozilla::WritingMode aWM,
1891 : mozilla::LogicalSide aSide) const
1892 : {
1893 1307 : return GetUnit(aWM.PhysicalSide(aSide));
1894 : }
1895 :
1896 77 : inline nsStyleUnit nsStyleSides::GetIStartUnit(mozilla::WritingMode aWM) const
1897 : {
1898 77 : return GetUnit(aWM, mozilla::eLogicalSideIStart);
1899 : }
1900 :
1901 77 : inline nsStyleUnit nsStyleSides::GetBStartUnit(mozilla::WritingMode aWM) const
1902 : {
1903 77 : return GetUnit(aWM, mozilla::eLogicalSideBStart);
1904 : }
1905 :
1906 77 : inline nsStyleUnit nsStyleSides::GetIEndUnit(mozilla::WritingMode aWM) const
1907 : {
1908 77 : return GetUnit(aWM, mozilla::eLogicalSideIEnd);
1909 : }
1910 :
1911 1076 : inline nsStyleUnit nsStyleSides::GetBEndUnit(mozilla::WritingMode aWM) const
1912 : {
1913 1076 : return GetUnit(aWM, mozilla::eLogicalSideBEnd);
1914 : }
1915 :
1916 0 : inline bool nsStyleSides::HasBlockAxisAuto(mozilla::WritingMode aWM) const
1917 : {
1918 0 : return GetBStartUnit(aWM) == eStyleUnit_Auto ||
1919 0 : GetBEndUnit(aWM) == eStyleUnit_Auto;
1920 : }
1921 :
1922 0 : inline bool nsStyleSides::HasInlineAxisAuto(mozilla::WritingMode aWM) const
1923 : {
1924 0 : return GetIStartUnit(aWM) == eStyleUnit_Auto ||
1925 0 : GetIEndUnit(aWM) == eStyleUnit_Auto;
1926 : }
1927 :
1928 10 : inline nsStyleCoord nsStyleSides::Get(mozilla::WritingMode aWM,
1929 : mozilla::LogicalSide aSide) const
1930 : {
1931 10 : return Get(aWM.PhysicalSide(aSide));
1932 : }
1933 :
1934 0 : inline nsStyleCoord nsStyleSides::GetIStart(mozilla::WritingMode aWM) const
1935 : {
1936 0 : return Get(aWM, mozilla::eLogicalSideIStart);
1937 : }
1938 :
1939 5 : inline nsStyleCoord nsStyleSides::GetBStart(mozilla::WritingMode aWM) const
1940 : {
1941 5 : return Get(aWM, mozilla::eLogicalSideBStart);
1942 : }
1943 :
1944 0 : inline nsStyleCoord nsStyleSides::GetIEnd(mozilla::WritingMode aWM) const
1945 : {
1946 0 : return Get(aWM, mozilla::eLogicalSideIEnd);
1947 : }
1948 :
1949 5 : inline nsStyleCoord nsStyleSides::GetBEnd(mozilla::WritingMode aWM) const
1950 : {
1951 5 : return Get(aWM, mozilla::eLogicalSideBEnd);
1952 : }
1953 :
1954 : // Definitions of inline methods for nsStylePosition, declared in
1955 : // nsStyleStruct.h but not defined there because they need WritingMode.
1956 : inline nsStyleCoord& nsStylePosition::ISize(mozilla::WritingMode aWM)
1957 : {
1958 : return aWM.IsVertical() ? mHeight : mWidth;
1959 : }
1960 : inline nsStyleCoord& nsStylePosition::MinISize(mozilla::WritingMode aWM)
1961 : {
1962 : return aWM.IsVertical() ? mMinHeight : mMinWidth;
1963 : }
1964 : inline nsStyleCoord& nsStylePosition::MaxISize(mozilla::WritingMode aWM)
1965 : {
1966 : return aWM.IsVertical() ? mMaxHeight : mMaxWidth;
1967 : }
1968 : inline nsStyleCoord& nsStylePosition::BSize(mozilla::WritingMode aWM)
1969 : {
1970 : return aWM.IsVertical() ? mWidth : mHeight;
1971 : }
1972 : inline nsStyleCoord& nsStylePosition::MinBSize(mozilla::WritingMode aWM)
1973 : {
1974 : return aWM.IsVertical() ? mMinWidth : mMinHeight;
1975 : }
1976 : inline nsStyleCoord& nsStylePosition::MaxBSize(mozilla::WritingMode aWM)
1977 : {
1978 : return aWM.IsVertical() ? mMaxWidth : mMaxHeight;
1979 : }
1980 :
1981 : inline const nsStyleCoord&
1982 728 : nsStylePosition::ISize(mozilla::WritingMode aWM) const
1983 : {
1984 728 : return aWM.IsVertical() ? mHeight : mWidth;
1985 : }
1986 : inline const nsStyleCoord&
1987 792 : nsStylePosition::MinISize(mozilla::WritingMode aWM) const
1988 : {
1989 792 : return aWM.IsVertical() ? mMinHeight : mMinWidth;
1990 : }
1991 : inline const nsStyleCoord&
1992 792 : nsStylePosition::MaxISize(mozilla::WritingMode aWM) const
1993 : {
1994 792 : return aWM.IsVertical() ? mMaxHeight : mMaxWidth;
1995 : }
1996 : inline const nsStyleCoord&
1997 2527 : nsStylePosition::BSize(mozilla::WritingMode aWM) const
1998 : {
1999 2527 : return aWM.IsVertical() ? mWidth : mHeight;
2000 : }
2001 : inline const nsStyleCoord&
2002 430 : nsStylePosition::MinBSize(mozilla::WritingMode aWM) const
2003 : {
2004 430 : return aWM.IsVertical() ? mMinWidth : mMinHeight;
2005 : }
2006 : inline const nsStyleCoord&
2007 1496 : nsStylePosition::MaxBSize(mozilla::WritingMode aWM) const
2008 : {
2009 1496 : return aWM.IsVertical() ? mMaxWidth : mMaxHeight;
2010 : }
2011 :
2012 : inline bool
2013 0 : nsStylePosition::ISizeDependsOnContainer(mozilla::WritingMode aWM) const
2014 : {
2015 0 : return aWM.IsVertical() ? HeightDependsOnContainer()
2016 0 : : WidthDependsOnContainer();
2017 : }
2018 : inline bool
2019 0 : nsStylePosition::MinISizeDependsOnContainer(mozilla::WritingMode aWM) const
2020 : {
2021 0 : return aWM.IsVertical() ? MinHeightDependsOnContainer()
2022 0 : : MinWidthDependsOnContainer();
2023 : }
2024 : inline bool
2025 0 : nsStylePosition::MaxISizeDependsOnContainer(mozilla::WritingMode aWM) const
2026 : {
2027 0 : return aWM.IsVertical() ? MaxHeightDependsOnContainer()
2028 0 : : MaxWidthDependsOnContainer();
2029 : }
2030 : inline bool
2031 1009 : nsStylePosition::BSizeDependsOnContainer(mozilla::WritingMode aWM) const
2032 : {
2033 1009 : return aWM.IsVertical() ? WidthDependsOnContainer()
2034 1009 : : HeightDependsOnContainer();
2035 : }
2036 : inline bool
2037 1001 : nsStylePosition::MinBSizeDependsOnContainer(mozilla::WritingMode aWM) const
2038 : {
2039 1001 : return aWM.IsVertical() ? MinWidthDependsOnContainer()
2040 1001 : : MinHeightDependsOnContainer();
2041 : }
2042 : inline bool
2043 1001 : nsStylePosition::MaxBSizeDependsOnContainer(mozilla::WritingMode aWM) const
2044 : {
2045 1001 : return aWM.IsVertical() ? MaxWidthDependsOnContainer()
2046 1001 : : MaxHeightDependsOnContainer();
2047 : }
2048 :
2049 : inline mozilla::StyleFloat
2050 0 : nsStyleDisplay::PhysicalFloats(mozilla::WritingMode aWM) const
2051 : {
2052 : using StyleFloat = mozilla::StyleFloat;
2053 0 : if (mFloat == StyleFloat::InlineStart) {
2054 0 : return aWM.IsBidiLTR() ? StyleFloat::Left : StyleFloat::Right;
2055 : }
2056 0 : if (mFloat == StyleFloat::InlineEnd) {
2057 0 : return aWM.IsBidiLTR() ? StyleFloat::Right : StyleFloat::Left;
2058 : }
2059 0 : return mFloat;
2060 : }
2061 :
2062 : inline mozilla::StyleClear
2063 19 : nsStyleDisplay::PhysicalBreakType(mozilla::WritingMode aWM) const
2064 : {
2065 : using StyleClear = mozilla::StyleClear;
2066 19 : if (mBreakType == StyleClear::InlineStart) {
2067 0 : return aWM.IsBidiLTR() ? StyleClear::Left : StyleClear::Right;
2068 : }
2069 19 : if (mBreakType == StyleClear::InlineEnd) {
2070 0 : return aWM.IsBidiLTR() ? StyleClear::Right : StyleClear::Left;
2071 : }
2072 19 : return mBreakType;
2073 : }
2074 :
2075 : inline bool
2076 0 : nsStyleMargin::HasBlockAxisAuto(mozilla::WritingMode aWM) const
2077 : {
2078 0 : return mMargin.HasBlockAxisAuto(aWM);
2079 : }
2080 : inline bool
2081 0 : nsStyleMargin::HasInlineAxisAuto(mozilla::WritingMode aWM) const
2082 : {
2083 0 : return mMargin.HasInlineAxisAuto(aWM);
2084 : }
2085 :
2086 : #endif // WritingModes_h_
|