michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef WritingModes_h_ michael@0: #define WritingModes_h_ michael@0: michael@0: #include "nsRect.h" michael@0: #include "nsStyleStruct.h" michael@0: michael@0: // If WRITING_MODE_VERTICAL_ENABLED is defined, we will attempt to support michael@0: // the vertical writing-mode values; if it is not defined, then michael@0: // WritingMode.IsVertical() will be hard-coded to return false, allowing michael@0: // many conditional branches to be optimized away while we're in the process michael@0: // of transitioning layout to use writing-mode and logical directions, but michael@0: // not yet ready to ship vertical support. michael@0: michael@0: /* #define WRITING_MODE_VERTICAL_ENABLED 1 */ michael@0: michael@0: // It is the caller's responsibility to operate on logical-coordinate objects michael@0: // with matched writing modes. Failure to do so will be a runtime bug; the michael@0: // compiler can't catch it, but in debug mode, we'll throw an assertion. michael@0: // NOTE that in non-debug builds, a writing mode mismatch error will NOT be michael@0: // detected, yet the results will be nonsense (and may lead to further layout michael@0: // failures). Therefore, it is important to test (and fuzz-test) writing-mode michael@0: // support using debug builds. michael@0: michael@0: // Methods in logical-coordinate classes that take another logical-coordinate michael@0: // object as a parameter should call CHECK_WRITING_MODE on it to verify that michael@0: // the writing modes match. michael@0: // (In some cases, there are internal (private) methods that don't do this; michael@0: // such methods should only be used by other methods that have already checked michael@0: // the writing modes.) michael@0: michael@0: #define CHECK_WRITING_MODE(param) \ michael@0: NS_ASSERTION(param == mWritingMode, "writing-mode mismatch") michael@0: michael@0: /** michael@0: * mozilla::WritingMode is an immutable class representing a michael@0: * writing mode. michael@0: * michael@0: * It efficiently stores the writing mode and can rapidly compute michael@0: * interesting things about it for use in layout. michael@0: * michael@0: * Writing modes are computed from the CSS 'direction', michael@0: * 'writing-mode', and 'text-orientation' properties. michael@0: * See CSS3 Writing Modes for more information michael@0: * http://www.w3.org/TR/css3-writing-modes/ michael@0: */ michael@0: michael@0: namespace mozilla { michael@0: michael@0: class WritingMode { michael@0: public: michael@0: /** michael@0: * Absolute inline flow direction michael@0: */ michael@0: enum InlineDir { michael@0: eInlineLTR = 0x00, // text flows horizontally left to right michael@0: eInlineRTL = 0x02, // text flows horizontally right to left michael@0: eInlineTTB = 0x01, // text flows vertically top to bottom michael@0: eInlineBTT = 0x03, // text flows vertically bottom to top michael@0: }; michael@0: michael@0: /** michael@0: * Absolute block flow direction michael@0: */ michael@0: enum BlockDir { michael@0: eBlockTB = 0x00, // horizontal lines stack top to bottom michael@0: eBlockRL = 0x01, // vertical lines stack right to left michael@0: eBlockLR = 0x05, // vertical lines stack left to right michael@0: }; michael@0: michael@0: /** michael@0: * Line-relative (bidi-relative) inline flow direction michael@0: */ michael@0: enum BidiDir { michael@0: eBidiLTR = 0x00, // inline flow matches bidi LTR text michael@0: eBidiRTL = 0x10, // inline flow matches bidi RTL text michael@0: }; michael@0: michael@0: /** michael@0: * Unknown writing mode (should never actually be stored or used anywhere). michael@0: */ michael@0: enum { michael@0: eUnknownWritingMode = 0xff michael@0: }; michael@0: michael@0: /** michael@0: * Return the absolute inline flow direction as an InlineDir michael@0: */ michael@0: InlineDir GetInlineDir() const { return InlineDir(mWritingMode & eInlineMask); } michael@0: michael@0: /** michael@0: * Return the absolute block flow direction as a BlockDir michael@0: */ michael@0: BlockDir GetBlockDir() const { return BlockDir(mWritingMode & eBlockMask); } michael@0: michael@0: /** michael@0: * Return the line-relative inline flow direction as a BidiDir michael@0: */ michael@0: BidiDir GetBidiDir() const { return BidiDir(mWritingMode & eBidiMask); } michael@0: michael@0: /** michael@0: * Return true if LTR. (Convenience method) michael@0: */ michael@0: bool IsBidiLTR() const { return eBidiLTR == (mWritingMode & eBidiMask); } michael@0: michael@0: /** michael@0: * True if vertical-mode block direction is LR (convenience method). michael@0: */ michael@0: bool IsVerticalLR() const { return eBlockLR == (mWritingMode & eBlockMask); } michael@0: michael@0: /** michael@0: * True if vertical writing mode, i.e. when michael@0: * writing-mode: vertical-lr | vertical-rl. michael@0: */ michael@0: #ifdef WRITING_MODE_VERTICAL_ENABLED michael@0: bool IsVertical() const { return !!(mWritingMode & eOrientationMask); } michael@0: #else michael@0: bool IsVertical() const { return false; } michael@0: #endif michael@0: michael@0: /** michael@0: * True if line-over/line-under are inverted from block-start/block-end. michael@0: * This is true when michael@0: * - writing-mode is vertical-rl && text-orientation is sideways-left michael@0: * - writing-mode is vertical-lr && text-orientation is not sideways-left michael@0: */ michael@0: #ifdef WRITING_MODE_VERTICAL_ENABLED michael@0: bool IsLineInverted() const { return !!(mWritingMode & eLineOrientMask); } michael@0: #else michael@0: bool IsLineInverted() const { return false; } michael@0: #endif michael@0: michael@0: /** michael@0: * Block-axis flow-relative to line-relative factor. michael@0: * May be used as a multiplication factor for block-axis coordinates michael@0: * to convert between flow- and line-relative coordinate systems (e.g. michael@0: * positioning an over- or under-line decoration). michael@0: */ michael@0: int FlowRelativeToLineRelativeFactor() const michael@0: { michael@0: return IsLineInverted() ? -1 : 1; michael@0: } michael@0: michael@0: /** michael@0: * Default constructor gives us a horizontal, LTR writing mode. michael@0: * XXX We will probably eliminate this and require explicit initialization michael@0: * in all cases once transition is complete. michael@0: */ michael@0: WritingMode() michael@0: : mWritingMode(0) michael@0: { } michael@0: michael@0: /** michael@0: * Construct writing mode based on a style context michael@0: */ michael@0: WritingMode(const nsStyleVisibility* aStyleVisibility) michael@0: { michael@0: NS_ASSERTION(aStyleVisibility, "we need an nsStyleVisibility here"); michael@0: michael@0: #ifdef WRITING_MODE_VERTICAL_ENABLED michael@0: switch (aStyleVisibility->mWritingMode) { michael@0: case NS_STYLE_WRITING_MODE_HORIZONTAL_TB: michael@0: mWritingMode = 0; michael@0: break; michael@0: michael@0: case NS_STYLE_WRITING_MODE_VERTICAL_LR: michael@0: mWritingMode = eBlockFlowMask | michael@0: eLineOrientMask | //XXX needs update when text-orientation added michael@0: eOrientationMask; michael@0: break; michael@0: michael@0: case NS_STYLE_WRITING_MODE_VERTICAL_RL: michael@0: mWritingMode = eOrientationMask; michael@0: break; michael@0: michael@0: default: michael@0: NS_NOTREACHED("unknown writing mode!"); michael@0: mWritingMode = 0; michael@0: break; michael@0: } michael@0: #else michael@0: mWritingMode = 0; michael@0: #endif michael@0: michael@0: if (NS_STYLE_DIRECTION_RTL == aStyleVisibility->mDirection) { michael@0: mWritingMode |= eInlineFlowMask | //XXX needs update when text-orientation added michael@0: eBidiMask; michael@0: } michael@0: } michael@0: michael@0: // For unicode-bidi: plaintext, reset the direction of the writing mode from michael@0: // the bidi paragraph level of the content michael@0: michael@0: //XXX change uint8_t to UBiDiLevel after bug 924851 michael@0: void SetDirectionFromBidiLevel(uint8_t level) michael@0: { michael@0: if (level & 1) { michael@0: // odd level, set RTL michael@0: mWritingMode |= eBidiMask; michael@0: } else { michael@0: // even level, set LTR michael@0: mWritingMode &= ~eBidiMask; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Compare two WritingModes for equality. michael@0: */ michael@0: bool operator==(const WritingMode& aOther) const michael@0: { michael@0: return mWritingMode == aOther.mWritingMode; michael@0: } michael@0: michael@0: private: michael@0: friend class LogicalPoint; michael@0: friend class LogicalSize; michael@0: friend class LogicalMargin; michael@0: friend class LogicalRect; michael@0: michael@0: /** michael@0: * Return a WritingMode representing an unknown value. michael@0: */ michael@0: static inline WritingMode Unknown() michael@0: { michael@0: return WritingMode(eUnknownWritingMode); michael@0: } michael@0: michael@0: /** michael@0: * Constructing a WritingMode with an arbitrary value is a private operation michael@0: * currently only used by the Unknown() static method. michael@0: */ michael@0: WritingMode(uint8_t aValue) michael@0: : mWritingMode(aValue) michael@0: { } michael@0: michael@0: uint8_t mWritingMode; michael@0: michael@0: enum Masks { michael@0: // Masks for our bits; true chosen as opposite of commonest case michael@0: eOrientationMask = 0x01, // true means vertical text michael@0: eInlineFlowMask = 0x02, // true means absolute RTL/BTT (against physical coords) michael@0: eBlockFlowMask = 0x04, // true means vertical-LR (or horizontal-BT if added) michael@0: eLineOrientMask = 0x08, // true means over != block-start michael@0: eBidiMask = 0x10, // true means line-relative RTL (bidi RTL) michael@0: // Note: We have one excess bit of info; WritingMode can pack into 4 bits. michael@0: // But since we have space, we're caching interesting things for fast access. michael@0: michael@0: // Masks for output enums michael@0: eInlineMask = 0x03, michael@0: eBlockMask = 0x05 michael@0: }; michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * Logical-coordinate classes: michael@0: * michael@0: * There are three sets of coordinate space: michael@0: * - physical (top, left, bottom, right) michael@0: * relative to graphics coord system michael@0: * - flow-relative (block-start, inline-start, block-end, inline-end) michael@0: * relative to block/inline flow directions michael@0: * - line-relative (line-over, line-left, line-under, line-right) michael@0: * relative to glyph orientation / inline bidi directions michael@0: * See CSS3 Writing Modes for more information michael@0: * http://www.w3.org/TR/css3-writing-modes/#abstract-box michael@0: * michael@0: * For shorthand, B represents the block-axis michael@0: * I represents the inline-axis michael@0: * michael@0: * The flow-relative geometric classes store coords in flow-relative space. michael@0: * They use a private ns{Point,Size,Rect,Margin} member to store the actual michael@0: * coordinate values, but reinterpret them as logical instead of physical. michael@0: * This allows us to easily perform calculations in logical space (provided michael@0: * writing modes of the operands match), by simply mapping to nsPoint (etc) michael@0: * methods. michael@0: * michael@0: * Physical-coordinate accessors/setters are responsible to translate these michael@0: * internal logical values as necessary. michael@0: * michael@0: * In DEBUG builds, the logical types store their WritingMode and check michael@0: * that the same WritingMode is passed whenever callers ask them to do a michael@0: * writing-mode-dependent operation. Non-DEBUG builds do NOT check this, michael@0: * to avoid the overhead of storing WritingMode fields. michael@0: * michael@0: * Open question: do we need a different set optimized for line-relative michael@0: * math, for use in nsLineLayout and the like? Or is multiplying values michael@0: * by FlowRelativeToLineRelativeFactor() enough? michael@0: */ michael@0: michael@0: /** michael@0: * Flow-relative point michael@0: */ michael@0: class LogicalPoint { michael@0: public: michael@0: LogicalPoint(WritingMode aWritingMode) michael@0: : michael@0: #ifdef DEBUG michael@0: mWritingMode(aWritingMode), michael@0: #endif michael@0: mPoint(0, 0) michael@0: { } michael@0: michael@0: // Construct from a writing mode and individual coordinates (which MUST be michael@0: // values in that writing mode, NOT physical coordinates!) michael@0: LogicalPoint(WritingMode aWritingMode, nscoord aI, nscoord aB) michael@0: : michael@0: #ifdef DEBUG michael@0: mWritingMode(aWritingMode), michael@0: #endif michael@0: mPoint(aI, aB) michael@0: { } michael@0: michael@0: // Construct from a writing mode and a physical point, within a given michael@0: // containing rectangle's width (defining the conversion between LTR michael@0: // and RTL coordinates). michael@0: LogicalPoint(WritingMode aWritingMode, michael@0: const nsPoint& aPoint, michael@0: nscoord aContainerWidth) michael@0: #ifdef DEBUG michael@0: : mWritingMode(aWritingMode) michael@0: #endif michael@0: { michael@0: if (aWritingMode.IsVertical()) { michael@0: I() = aPoint.y; michael@0: B() = aWritingMode.IsVerticalLR() ? aPoint.x : aContainerWidth - aPoint.x; michael@0: } else { michael@0: I() = aWritingMode.IsBidiLTR() ? aPoint.x : aContainerWidth - aPoint.x; michael@0: B() = aPoint.y; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Read-only (const) access to the coordinates, in both logical michael@0: * and physical terms. michael@0: */ michael@0: nscoord I(WritingMode aWritingMode) const // inline-axis michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mPoint.x; michael@0: } michael@0: nscoord B(WritingMode aWritingMode) const // block-axis michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mPoint.y; michael@0: } michael@0: michael@0: nscoord X(WritingMode aWritingMode, nscoord aContainerWidth) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: if (aWritingMode.IsVertical()) { michael@0: return aWritingMode.IsVerticalLR() ? B() : aContainerWidth - B(); michael@0: } else { michael@0: return aWritingMode.IsBidiLTR() ? I() : aContainerWidth - I(); michael@0: } michael@0: } michael@0: nscoord Y(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? I() : B(); michael@0: } michael@0: michael@0: /** michael@0: * These non-const accessors return a reference (lvalue) that can be michael@0: * assigned to by callers. michael@0: */ michael@0: nscoord& I(WritingMode aWritingMode) // inline-axis michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mPoint.x; michael@0: } michael@0: nscoord& B(WritingMode aWritingMode) // block-axis michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mPoint.y; michael@0: } michael@0: michael@0: /** michael@0: * Setters for the physical coordinates. michael@0: */ michael@0: void SetX(WritingMode aWritingMode, nscoord aX, nscoord aContainerWidth) michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: if (aWritingMode.IsVertical()) { michael@0: B() = aWritingMode.IsVerticalLR() ? aX : aContainerWidth - aX; michael@0: } else { michael@0: I() = aWritingMode.IsBidiLTR() ? aX : aContainerWidth - aX; michael@0: } michael@0: } michael@0: void SetY(WritingMode aWritingMode, nscoord aY) michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: if (aWritingMode.IsVertical()) { michael@0: B() = aY; michael@0: } else { michael@0: I() = aY; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Return a physical point corresponding to our logical coordinates, michael@0: * converted according to our writing mode. michael@0: */ michael@0: nsPoint GetPhysicalPoint(WritingMode aWritingMode, michael@0: nscoord aContainerWidth) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: if (aWritingMode.IsVertical()) { michael@0: return nsPoint(aWritingMode.IsVerticalLR() ? B() : aContainerWidth - B(), michael@0: I()); michael@0: } else { michael@0: return nsPoint(aWritingMode.IsBidiLTR() ? I() : aContainerWidth - I(), michael@0: B()); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Return the equivalent point in a different writing mode. michael@0: */ michael@0: LogicalPoint ConvertTo(WritingMode aToMode, WritingMode aFromMode, michael@0: nscoord aContainerWidth) const michael@0: { michael@0: CHECK_WRITING_MODE(aFromMode); michael@0: return aToMode == aFromMode ? michael@0: *this : LogicalPoint(aToMode, michael@0: GetPhysicalPoint(aFromMode, aContainerWidth), michael@0: aContainerWidth); michael@0: } michael@0: michael@0: LogicalPoint operator+(const LogicalPoint& aOther) const michael@0: { michael@0: CHECK_WRITING_MODE(aOther.GetWritingMode()); michael@0: // In non-debug builds, LogicalPoint does not store the WritingMode, michael@0: // so the first parameter here (which will always be eUnknownWritingMode) michael@0: // is ignored. michael@0: return LogicalPoint(GetWritingMode(), michael@0: mPoint.x + aOther.mPoint.x, michael@0: mPoint.y + aOther.mPoint.y); michael@0: } michael@0: michael@0: private: michael@0: friend class LogicalRect; michael@0: michael@0: /** michael@0: * NOTE that in non-DEBUG builds, GetWritingMode() always returns michael@0: * eUnknownWritingMode, as the current mode is not stored in the logical- michael@0: * geometry classes. Therefore, this method is private; it is used ONLY michael@0: * by the DEBUG-mode checking macros in this class and its friends; michael@0: * other code is not allowed to ask a logical point for its writing mode, michael@0: * as this info will simply not be available in non-DEBUG builds. michael@0: * michael@0: * Also, in non-DEBUG builds, CHECK_WRITING_MODE does nothing, and the michael@0: * WritingMode parameter to logical methods will generally be optimized michael@0: * away altogether. michael@0: */ michael@0: #ifdef DEBUG michael@0: WritingMode GetWritingMode() const { return mWritingMode; } michael@0: #else michael@0: WritingMode GetWritingMode() const { return WritingMode::Unknown(); } michael@0: #endif michael@0: michael@0: // We don't allow construction of a LogicalPoint with no writing mode. michael@0: LogicalPoint() MOZ_DELETE; michael@0: michael@0: // Accessors that don't take or check a WritingMode value. michael@0: // These are for internal use only; they are called by methods that have michael@0: // themselves already checked the WritingMode passed by the caller. michael@0: nscoord I() const // inline-axis michael@0: { michael@0: return mPoint.x; michael@0: } michael@0: nscoord B() const // block-axis michael@0: { michael@0: return mPoint.y; michael@0: } michael@0: michael@0: nscoord& I() // inline-axis michael@0: { michael@0: return mPoint.x; michael@0: } michael@0: nscoord& B() // block-axis michael@0: { michael@0: return mPoint.y; michael@0: } michael@0: michael@0: WritingMode mWritingMode; michael@0: michael@0: // We use an nsPoint to hold the coordinates, but reinterpret its .x and .y michael@0: // fields as the inline and block directions. Hence, this is not exposed michael@0: // directly, but only through accessors that will map them according to the michael@0: // writing mode. michael@0: nsPoint mPoint; michael@0: }; michael@0: michael@0: /** michael@0: * Flow-relative size michael@0: */ michael@0: class LogicalSize { michael@0: public: michael@0: LogicalSize(WritingMode aWritingMode) michael@0: : michael@0: #ifdef DEBUG michael@0: mWritingMode(aWritingMode), michael@0: #endif michael@0: mSize(0, 0) michael@0: { } michael@0: michael@0: LogicalSize(WritingMode aWritingMode, nscoord aISize, nscoord aBSize) michael@0: : michael@0: #ifdef DEBUG michael@0: mWritingMode(aWritingMode), michael@0: #endif michael@0: mSize(aISize, aBSize) michael@0: { } michael@0: michael@0: LogicalSize(WritingMode aWritingMode, const nsSize& aPhysicalSize) michael@0: #ifdef DEBUG michael@0: : mWritingMode(aWritingMode) michael@0: #endif michael@0: { michael@0: if (aWritingMode.IsVertical()) { michael@0: ISize() = aPhysicalSize.height; michael@0: BSize() = aPhysicalSize.width; michael@0: } else { michael@0: ISize() = aPhysicalSize.width; michael@0: BSize() = aPhysicalSize.height; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Dimensions in logical and physical terms michael@0: */ michael@0: nscoord ISize(WritingMode aWritingMode) const // inline-size michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mSize.width; michael@0: } michael@0: nscoord BSize(WritingMode aWritingMode) const // block-size michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mSize.height; michael@0: } michael@0: michael@0: nscoord Width(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? BSize() : ISize(); michael@0: } michael@0: nscoord Height(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? ISize() : BSize(); michael@0: } michael@0: michael@0: /** michael@0: * Writable references to the logical dimensions michael@0: */ michael@0: nscoord& ISize(WritingMode aWritingMode) // inline-size michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mSize.width; michael@0: } michael@0: nscoord& BSize(WritingMode aWritingMode) // block-size michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mSize.height; michael@0: } michael@0: michael@0: /** michael@0: * Setters for the physical dimensions michael@0: */ michael@0: void SetWidth(WritingMode aWritingMode, nscoord aWidth) michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: if (aWritingMode.IsVertical()) { michael@0: BSize() = aWidth; michael@0: } else { michael@0: ISize() = aWidth; michael@0: } michael@0: } michael@0: void SetHeight(WritingMode aWritingMode, nscoord aHeight) michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: if (aWritingMode.IsVertical()) { michael@0: ISize() = aHeight; michael@0: } else { michael@0: BSize() = aHeight; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Return an nsSize containing our physical dimensions michael@0: */ michael@0: nsSize GetPhysicalSize(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? michael@0: nsSize(BSize(), ISize()) : nsSize(ISize(), BSize()); michael@0: } michael@0: michael@0: /** michael@0: * Return a LogicalSize representing this size in a different writing mode michael@0: */ michael@0: LogicalSize ConvertTo(WritingMode aToMode, WritingMode aFromMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aFromMode); michael@0: return aToMode == aFromMode ? michael@0: *this : LogicalSize(aToMode, GetPhysicalSize(aFromMode)); michael@0: } michael@0: michael@0: private: michael@0: friend class LogicalRect; michael@0: michael@0: LogicalSize() MOZ_DELETE; michael@0: michael@0: #ifdef DEBUG michael@0: WritingMode GetWritingMode() const { return mWritingMode; } michael@0: #else michael@0: WritingMode GetWritingMode() const { return WritingMode::Unknown(); } michael@0: #endif michael@0: michael@0: nscoord ISize() const // inline-size michael@0: { michael@0: return mSize.width; michael@0: } michael@0: nscoord BSize() const // block-size michael@0: { michael@0: return mSize.height; michael@0: } michael@0: michael@0: nscoord& ISize() // inline-size michael@0: { michael@0: return mSize.width; michael@0: } michael@0: nscoord& BSize() // block-size michael@0: { michael@0: return mSize.height; michael@0: } michael@0: michael@0: WritingMode mWritingMode; michael@0: nsSize mSize; michael@0: }; michael@0: michael@0: /** michael@0: * Flow-relative margin michael@0: */ michael@0: class LogicalMargin { michael@0: public: michael@0: LogicalMargin(WritingMode aWritingMode) michael@0: : michael@0: #ifdef DEBUG michael@0: mWritingMode(aWritingMode), michael@0: #endif michael@0: mMargin(0, 0, 0, 0) michael@0: { } michael@0: michael@0: LogicalMargin(WritingMode aWritingMode, michael@0: nscoord aBStart, nscoord aIEnd, michael@0: nscoord aBEnd, nscoord aIStart) michael@0: : michael@0: #ifdef DEBUG michael@0: mWritingMode(aWritingMode), michael@0: #endif michael@0: mMargin(aBStart, aIEnd, aBEnd, aIStart) michael@0: { } michael@0: michael@0: LogicalMargin(WritingMode aWritingMode, const nsMargin& aPhysicalMargin) michael@0: #ifdef DEBUG michael@0: : mWritingMode(aWritingMode) michael@0: #endif michael@0: { michael@0: if (aWritingMode.IsVertical()) { michael@0: if (aWritingMode.IsVerticalLR()) { michael@0: mMargin.top = aPhysicalMargin.left; michael@0: mMargin.bottom = aPhysicalMargin.right; michael@0: } else { michael@0: mMargin.top = aPhysicalMargin.right; michael@0: mMargin.bottom = aPhysicalMargin.left; michael@0: } michael@0: if (aWritingMode.IsBidiLTR()) { michael@0: mMargin.left = aPhysicalMargin.top; michael@0: mMargin.right = aPhysicalMargin.bottom; michael@0: } else { michael@0: mMargin.left = aPhysicalMargin.bottom; michael@0: mMargin.right = aPhysicalMargin.top; michael@0: } michael@0: } else { michael@0: mMargin.top = aPhysicalMargin.top; michael@0: mMargin.bottom = aPhysicalMargin.bottom; michael@0: if (aWritingMode.IsBidiLTR()) { michael@0: mMargin.left = aPhysicalMargin.left; michael@0: mMargin.right = aPhysicalMargin.right; michael@0: } else { michael@0: mMargin.left = aPhysicalMargin.right; michael@0: mMargin.right = aPhysicalMargin.left; michael@0: } michael@0: } michael@0: } michael@0: michael@0: nscoord IStart(WritingMode aWritingMode) const // inline-start margin michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mMargin.left; michael@0: } michael@0: nscoord IEnd(WritingMode aWritingMode) const // inline-end margin michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mMargin.right; michael@0: } michael@0: nscoord BStart(WritingMode aWritingMode) const // block-start margin michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mMargin.top; michael@0: } michael@0: nscoord BEnd(WritingMode aWritingMode) const // block-end margin michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mMargin.bottom; michael@0: } michael@0: michael@0: nscoord& IStart(WritingMode aWritingMode) // inline-start margin michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mMargin.left; michael@0: } michael@0: nscoord& IEnd(WritingMode aWritingMode) // inline-end margin michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mMargin.right; michael@0: } michael@0: nscoord& BStart(WritingMode aWritingMode) // block-start margin michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mMargin.top; michael@0: } michael@0: nscoord& BEnd(WritingMode aWritingMode) // block-end margin michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mMargin.bottom; michael@0: } michael@0: michael@0: nscoord IStartEnd(WritingMode aWritingMode) const // inline margins michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mMargin.LeftRight(); michael@0: } michael@0: nscoord BStartEnd(WritingMode aWritingMode) const // block margins michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mMargin.TopBottom(); michael@0: } michael@0: michael@0: /** michael@0: * Accessors for physical margins, using our writing mode to convert from michael@0: * logical values. michael@0: */ michael@0: nscoord Top(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? michael@0: (aWritingMode.IsBidiLTR() ? IStart() : IEnd()) : BStart(); michael@0: } michael@0: michael@0: nscoord Bottom(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? michael@0: (aWritingMode.IsBidiLTR() ? IEnd() : IStart()) : BEnd(); michael@0: } michael@0: michael@0: nscoord Left(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? michael@0: (aWritingMode.IsVerticalLR() ? BStart() : BEnd()) : michael@0: (aWritingMode.IsBidiLTR() ? IStart() : IEnd()); michael@0: } michael@0: michael@0: nscoord Right(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? michael@0: (aWritingMode.IsVerticalLR() ? BEnd() : BStart()) : michael@0: (aWritingMode.IsBidiLTR() ? IEnd() : IStart()); michael@0: } michael@0: michael@0: nscoord LeftRight(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? BStartEnd() : IStartEnd(); michael@0: } michael@0: michael@0: nscoord TopBottom(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? IStartEnd() : BStartEnd(); michael@0: } michael@0: michael@0: void SizeTo(WritingMode aWritingMode, michael@0: nscoord aBStart, nscoord aIEnd, nscoord aBEnd, nscoord aIStart) michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: mMargin.SizeTo(aBStart, aIEnd, aBEnd, aIStart); michael@0: } michael@0: michael@0: /** michael@0: * Return an nsMargin containing our physical coordinates michael@0: */ michael@0: nsMargin GetPhysicalMargin(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? michael@0: (aWritingMode.IsVerticalLR() ? michael@0: nsMargin(IStart(), BEnd(), IEnd(), BStart()) : michael@0: nsMargin(IStart(), BStart(), IEnd(), BEnd())) : michael@0: (aWritingMode.IsBidiLTR() ? michael@0: nsMargin(BStart(), IEnd(), BEnd(), IStart()) : michael@0: nsMargin(BStart(), IStart(), BEnd(), IEnd())); michael@0: } michael@0: michael@0: /** michael@0: * Return a LogicalMargin representing this margin in a different michael@0: * writing mode michael@0: */ michael@0: LogicalMargin ConvertTo(WritingMode aToMode, WritingMode aFromMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aFromMode); michael@0: return aToMode == aFromMode ? michael@0: *this : LogicalMargin(aToMode, GetPhysicalMargin(aFromMode)); michael@0: } michael@0: michael@0: bool IsEmpty() const michael@0: { michael@0: return (mMargin.left == 0 && mMargin.top == 0 && michael@0: mMargin.right == 0 && mMargin.bottom == 0); michael@0: } michael@0: michael@0: LogicalMargin operator+(const LogicalMargin& aMargin) { michael@0: CHECK_WRITING_MODE(aMargin.GetWritingMode()); michael@0: return LogicalMargin(GetWritingMode(), michael@0: BStart() + aMargin.BStart(), michael@0: IEnd() + aMargin.IEnd(), michael@0: BEnd() + aMargin.BEnd(), michael@0: IStart() + aMargin.IStart()); michael@0: } michael@0: michael@0: LogicalMargin operator-(const LogicalMargin& aMargin) { michael@0: CHECK_WRITING_MODE(aMargin.GetWritingMode()); michael@0: return LogicalMargin(GetWritingMode(), michael@0: BStart() - aMargin.BStart(), michael@0: IEnd() - aMargin.IEnd(), michael@0: BEnd() - aMargin.BEnd(), michael@0: IStart() - aMargin.IStart()); michael@0: } michael@0: michael@0: private: michael@0: friend class LogicalRect; michael@0: michael@0: LogicalMargin() MOZ_DELETE; michael@0: michael@0: #ifdef DEBUG michael@0: WritingMode GetWritingMode() const { return mWritingMode; } michael@0: #else michael@0: WritingMode GetWritingMode() const { return WritingMode::Unknown(); } michael@0: #endif michael@0: michael@0: nscoord IStart() const // inline-start margin michael@0: { michael@0: return mMargin.left; michael@0: } michael@0: nscoord IEnd() const // inline-end margin michael@0: { michael@0: return mMargin.right; michael@0: } michael@0: nscoord BStart() const // block-start margin michael@0: { michael@0: return mMargin.top; michael@0: } michael@0: nscoord BEnd() const // block-end margin michael@0: { michael@0: return mMargin.bottom; michael@0: } michael@0: michael@0: nscoord& IStart() // inline-start margin michael@0: { michael@0: return mMargin.left; michael@0: } michael@0: nscoord& IEnd() // inline-end margin michael@0: { michael@0: return mMargin.right; michael@0: } michael@0: nscoord& BStart() // block-start margin michael@0: { michael@0: return mMargin.top; michael@0: } michael@0: nscoord& BEnd() // block-end margin michael@0: { michael@0: return mMargin.bottom; michael@0: } michael@0: michael@0: nscoord IStartEnd() const // inline margins michael@0: { michael@0: return mMargin.LeftRight(); michael@0: } michael@0: nscoord BStartEnd() const // block margins michael@0: { michael@0: return mMargin.TopBottom(); michael@0: } michael@0: michael@0: WritingMode mWritingMode; michael@0: nsMargin mMargin; michael@0: }; michael@0: michael@0: /** michael@0: * Flow-relative rectangle michael@0: */ michael@0: class LogicalRect { michael@0: public: michael@0: LogicalRect(WritingMode aWritingMode) michael@0: : michael@0: #ifdef DEBUG michael@0: mWritingMode(aWritingMode), michael@0: #endif michael@0: mRect(0, 0, 0, 0) michael@0: { } michael@0: michael@0: LogicalRect(WritingMode aWritingMode, michael@0: nscoord aIStart, nscoord aBStart, michael@0: nscoord aISize, nscoord aBSize) michael@0: : michael@0: #ifdef DEBUG michael@0: mWritingMode(aWritingMode), michael@0: #endif michael@0: mRect(aIStart, aBStart, aISize, aBSize) michael@0: { } michael@0: michael@0: LogicalRect(WritingMode aWritingMode, michael@0: const LogicalPoint& aOrigin, michael@0: const LogicalSize& aSize) michael@0: : michael@0: #ifdef DEBUG michael@0: mWritingMode(aWritingMode), michael@0: #endif michael@0: mRect(aOrigin.mPoint, aSize.mSize) michael@0: { michael@0: CHECK_WRITING_MODE(aOrigin.GetWritingMode()); michael@0: CHECK_WRITING_MODE(aSize.GetWritingMode()); michael@0: } michael@0: michael@0: LogicalRect(WritingMode aWritingMode, michael@0: const nsRect& aRect, michael@0: nscoord aContainerWidth) michael@0: #ifdef DEBUG michael@0: : mWritingMode(aWritingMode) michael@0: #endif michael@0: { michael@0: if (aWritingMode.IsVertical()) { michael@0: if (aWritingMode.IsVerticalLR()) { michael@0: mRect.y = aRect.x; michael@0: } else { michael@0: mRect.y = aContainerWidth - aRect.XMost(); michael@0: } michael@0: mRect.height = aRect.width; michael@0: mRect.x = aRect.y; michael@0: mRect.width = aRect.height; michael@0: } else { michael@0: if (aWritingMode.IsBidiLTR()) { michael@0: mRect.x = aRect.x; michael@0: } else { michael@0: mRect.x = aContainerWidth - aRect.XMost(); michael@0: } michael@0: mRect.width = aRect.width; michael@0: mRect.y = aRect.y; michael@0: mRect.height = aRect.height; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Inline- and block-dimension geometry. michael@0: */ michael@0: nscoord IStart(WritingMode aWritingMode) const // inline-start edge michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mRect.X(); michael@0: } michael@0: nscoord IEnd(WritingMode aWritingMode) const // inline-end edge michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mRect.XMost(); michael@0: } michael@0: nscoord ISize(WritingMode aWritingMode) const // inline-size michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mRect.Width(); michael@0: } michael@0: michael@0: nscoord BStart(WritingMode aWritingMode) const // block-start edge michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mRect.Y(); michael@0: } michael@0: nscoord BEnd(WritingMode aWritingMode) const // block-end edge michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mRect.YMost(); michael@0: } michael@0: nscoord BSize(WritingMode aWritingMode) const // block-size michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mRect.Height(); michael@0: } michael@0: michael@0: /** michael@0: * Writable (reference) accessors are only available for the basic logical michael@0: * fields (Start and Size), not derivatives like End. michael@0: */ michael@0: nscoord& IStart(WritingMode aWritingMode) // inline-start edge michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mRect.x; michael@0: } michael@0: nscoord& ISize(WritingMode aWritingMode) // inline-size michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mRect.width; michael@0: } michael@0: nscoord& BStart(WritingMode aWritingMode) // block-start edge michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mRect.y; michael@0: } michael@0: nscoord& BSize(WritingMode aWritingMode) // block-size michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return mRect.height; michael@0: } michael@0: michael@0: /** michael@0: * Physical coordinates of the rect. michael@0: */ michael@0: nscoord X(WritingMode aWritingMode, nscoord aContainerWidth) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: if (aWritingMode.IsVertical()) { michael@0: return aWritingMode.IsVerticalLR() ? michael@0: mRect.Y() : aContainerWidth - mRect.YMost(); michael@0: } else { michael@0: return aWritingMode.IsBidiLTR() ? michael@0: mRect.X() : aContainerWidth - mRect.XMost(); michael@0: } michael@0: } michael@0: michael@0: void SetX(WritingMode aWritingMode, nscoord aX, nscoord aContainerWidth) michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: if (aWritingMode.IsVertical()) { michael@0: if (aWritingMode.IsVerticalLR()) { michael@0: BStart() = aX; michael@0: } else { michael@0: BStart() = aContainerWidth - aX - BSize(); michael@0: } michael@0: } else { michael@0: if (aWritingMode.IsBidiLTR()) { michael@0: IStart() = aX; michael@0: } else { michael@0: IStart() = aContainerWidth - aX - ISize(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: nscoord Y(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? mRect.X() : mRect.Y(); michael@0: } michael@0: michael@0: void SetY(WritingMode aWritingMode, nscoord aY) michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: if (aWritingMode.IsVertical()) { michael@0: IStart() = aY; michael@0: } else { michael@0: BStart() = aY; michael@0: } michael@0: } michael@0: michael@0: nscoord Width(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? mRect.Height() : mRect.Width(); michael@0: } michael@0: michael@0: // When setting the Width of a rect, we keep its physical X-coord fixed michael@0: // and modify XMax. This means that in the RTL case, we'll be moving michael@0: // the IStart, so that IEnd remains constant. michael@0: void SetWidth(WritingMode aWritingMode, nscoord aWidth) michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: if (aWritingMode.IsVertical()) { michael@0: if (!aWritingMode.IsVerticalLR()) { michael@0: BStart() = BStart() + BSize() - aWidth; michael@0: } michael@0: BSize() = aWidth; michael@0: } else { michael@0: if (!aWritingMode.IsBidiLTR()) { michael@0: IStart() = IStart() + ISize() - aWidth; michael@0: } michael@0: ISize() = aWidth; michael@0: } michael@0: } michael@0: michael@0: nscoord Height(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? mRect.Width() : mRect.Height(); michael@0: } michael@0: michael@0: void SetHeight(WritingMode aWritingMode, nscoord aHeight) michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: if (aWritingMode.IsVertical()) { michael@0: ISize() = aHeight; michael@0: } else { michael@0: BSize() = aHeight; michael@0: } michael@0: } michael@0: michael@0: nscoord XMost(WritingMode aWritingMode, nscoord aContainerWidth) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: if (aWritingMode.IsVertical()) { michael@0: return aWritingMode.IsVerticalLR() ? michael@0: mRect.YMost() : aContainerWidth - mRect.Y(); michael@0: } else { michael@0: return aWritingMode.IsBidiLTR() ? michael@0: mRect.XMost() : aContainerWidth - mRect.X(); michael@0: } michael@0: } michael@0: michael@0: nscoord YMost(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsVertical() ? mRect.XMost() : mRect.YMost(); michael@0: } michael@0: michael@0: bool IsEmpty() const michael@0: { michael@0: return (mRect.x == 0 && mRect.y == 0 && michael@0: mRect.width == 0 && mRect.height == 0); michael@0: } michael@0: michael@0: bool IsZeroSize() const michael@0: { michael@0: return (mRect.width == 0 && mRect.height == 0); michael@0: } michael@0: michael@0: /* XXX are these correct? michael@0: nscoord ILeft(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsBidiLTR() ? IStart() : IEnd(); michael@0: } michael@0: nscoord IRight(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return aWritingMode.IsBidiLTR() ? IEnd() : IStart(); michael@0: } michael@0: */ michael@0: michael@0: LogicalPoint Origin(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return LogicalPoint(aWritingMode, IStart(), BStart()); michael@0: } michael@0: LogicalSize Size(WritingMode aWritingMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: return LogicalSize(aWritingMode, ISize(), BSize()); michael@0: } michael@0: michael@0: LogicalRect operator+(const LogicalPoint& aPoint) const michael@0: { michael@0: CHECK_WRITING_MODE(aPoint.GetWritingMode()); michael@0: return LogicalRect(GetWritingMode(), michael@0: IStart() + aPoint.I(), BStart() + aPoint.B(), michael@0: ISize(), BSize()); michael@0: } michael@0: michael@0: LogicalRect& operator+=(const LogicalPoint& aPoint) michael@0: { michael@0: CHECK_WRITING_MODE(aPoint.GetWritingMode()); michael@0: mRect += aPoint.mPoint; michael@0: return *this; michael@0: } michael@0: michael@0: LogicalRect operator-(const LogicalPoint& aPoint) const michael@0: { michael@0: CHECK_WRITING_MODE(aPoint.GetWritingMode()); michael@0: return LogicalRect(GetWritingMode(), michael@0: IStart() - aPoint.I(), BStart() - aPoint.B(), michael@0: ISize(), BSize()); michael@0: } michael@0: michael@0: LogicalRect& operator-=(const LogicalPoint& aPoint) michael@0: { michael@0: CHECK_WRITING_MODE(aPoint.GetWritingMode()); michael@0: mRect -= aPoint.mPoint; michael@0: return *this; michael@0: } michael@0: michael@0: void MoveBy(WritingMode aWritingMode, const LogicalPoint& aDelta) michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: CHECK_WRITING_MODE(aDelta.GetWritingMode()); michael@0: IStart() += aDelta.I(); michael@0: BStart() += aDelta.B(); michael@0: } michael@0: michael@0: void Inflate(nscoord aD) { mRect.Inflate(aD); } michael@0: void Inflate(nscoord aDI, nscoord aDB) { mRect.Inflate(aDI, aDB); } michael@0: void Inflate(WritingMode aWritingMode, const LogicalMargin& aMargin) michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: CHECK_WRITING_MODE(aMargin.GetWritingMode()); michael@0: mRect.Inflate(aMargin.mMargin); michael@0: } michael@0: michael@0: void Deflate(nscoord aD) { mRect.Deflate(aD); } michael@0: void Deflate(nscoord aDI, nscoord aDB) { mRect.Deflate(aDI, aDB); } michael@0: void Deflate(WritingMode aWritingMode, const LogicalMargin& aMargin) michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: CHECK_WRITING_MODE(aMargin.GetWritingMode()); michael@0: mRect.Deflate(aMargin.mMargin); michael@0: } michael@0: michael@0: /** michael@0: * Return an nsRect containing our physical coordinates within the given michael@0: * container width michael@0: */ michael@0: nsRect GetPhysicalRect(WritingMode aWritingMode, michael@0: nscoord aContainerWidth) const michael@0: { michael@0: CHECK_WRITING_MODE(aWritingMode); michael@0: if (aWritingMode.IsVertical()) { michael@0: return nsRect(aWritingMode.IsVerticalLR() ? michael@0: BStart() : aContainerWidth - BEnd(), michael@0: IStart(), BSize(), ISize()); michael@0: } else { michael@0: return nsRect(aWritingMode.IsBidiLTR() ? michael@0: IStart() : aContainerWidth - IEnd(), michael@0: BStart(), ISize(), BSize()); michael@0: } michael@0: } michael@0: michael@0: #if 0 // XXX this would require aContainerWidth as well michael@0: /** michael@0: * Return a LogicalRect representing this rect in a different writing mode michael@0: */ michael@0: LogicalRect ConvertTo(WritingMode aToMode, WritingMode aFromMode) const michael@0: { michael@0: CHECK_WRITING_MODE(aFromMode); michael@0: return aToMode == aFromMode ? michael@0: *this : LogicalRect(aToMode, GetPhysicalRect(aFromMode)); michael@0: } michael@0: #endif michael@0: michael@0: private: michael@0: LogicalRect() MOZ_DELETE; michael@0: michael@0: #ifdef DEBUG michael@0: WritingMode GetWritingMode() const { return mWritingMode; } michael@0: #else michael@0: WritingMode GetWritingMode() const { return WritingMode::Unknown(); } michael@0: #endif michael@0: michael@0: nscoord IStart() const // inline-start edge michael@0: { michael@0: return mRect.X(); michael@0: } michael@0: nscoord IEnd() const // inline-end edge michael@0: { michael@0: return mRect.XMost(); michael@0: } michael@0: nscoord ISize() const // inline-size michael@0: { michael@0: return mRect.Width(); michael@0: } michael@0: michael@0: nscoord BStart() const // block-start edge michael@0: { michael@0: return mRect.Y(); michael@0: } michael@0: nscoord BEnd() const // block-end edge michael@0: { michael@0: return mRect.YMost(); michael@0: } michael@0: nscoord BSize() const // block-size michael@0: { michael@0: return mRect.Height(); michael@0: } michael@0: michael@0: nscoord& IStart() // inline-start edge michael@0: { michael@0: return mRect.x; michael@0: } michael@0: nscoord& ISize() // inline-size michael@0: { michael@0: return mRect.width; michael@0: } michael@0: nscoord& BStart() // block-start edge michael@0: { michael@0: return mRect.y; michael@0: } michael@0: nscoord& BSize() // block-size michael@0: { michael@0: return mRect.height; michael@0: } michael@0: michael@0: WritingMode mWritingMode; michael@0: nsRect mRect; michael@0: }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif // WritingModes_h_