/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_DashedCornerFinder_h_ #define mozilla_DashedCornerFinder_h_ #include "mozilla/gfx/2D.h" #include "mozilla/gfx/BezierUtils.h" namespace mozilla { // Calculate {OuterT_i, InnerT_i} for each 1 < i < n, that // (OuterL_i + InnerL_i) / 2 == dashLength * (W_i + W_{i-1}) / 2 // where // OuterP_i: OuterCurve(OuterT_i) // InnerP_i: InnerCurve(OuterT_i) // OuterL_i: Elliptic arc length between OuterP_i - OuterP_{i-1} // InnerL_i: Elliptic arc length between InnerP_i - InnerP_{i-1} // W_i = |OuterP_i - InnerP_i| // 1.0 < dashLength < 3.0 // // OuterP_1 OuterP_0 // _+__-----------+ OuterCurve // OuterP_2 __---- | OuterL_1 | // __+--- | | // __--- | OuterL_2 | | // OuterP_3 _-- | | W_1 | W_0 // _+ | | | // / \ W_2 | | | // / \ | | InnerL_1 | // | \ | InnerL_2|____-------+ InnerCurve // | \ |____----+ InnerP_0 // | . \ __---+ InnerP_1 // | \ / InnerP_2 // | . /+ InnerP_3 // | | // | . | // | | // | | // | | // OuterP_{n-1} +--------+ InnerP_{n-1} // | | // | | // | | // | | // | | // OuterP_n +--------+ InnerP_n // // Returns region with [OuterCurve((OuterT_{2j} + OuterT_{2j-1}) / 2), // OuterCurve((OuterT_{2j} + OuterT_{2j-1}) / 2), // InnerCurve((OuterT_{2j} + OuterT_{2j+1}) / 2), // InnerCurve((OuterT_{2j} + OuterT_{2j+1}) / 2)], // to start and end with half segment. // // _+__----+------+ OuterCurve // _+---- | |######| // __+---#| | |######| // _+---##|####| | |######| // _-- |#####|#####| | |#####| // _+ |#####|#####| | |#####| // / \ |#####|####| | |#####| // / \ |####|#####| | |#####| // | \ |####|####| |____-+-----+ InnerCurve // | \ |####|____+---+ // | . \ __+---+ // | \ / // | . /+ // | | // | . | // | | // | | // | | // +--------+ // | | // | | // +--------+ // |########| // |########| // +--------+ class DashedCornerFinder { typedef mozilla::gfx::Bezier Bezier; typedef mozilla::gfx::Float Float; typedef mozilla::gfx::Point Point; typedef mozilla::gfx::Size Size; public: struct Result { // Control points for the outer curve and the inner curve. // // outerSectionBezier // | // v _+ 3 // ___---#| // 0 +---#######| // |###########| // |###########| // |##########| // |##########| // |#########| // |#####____+ 3 // 0 +---- // ^ // | // innerSectionBezier Bezier outerSectionBezier; Bezier innerSectionBezier; Result(const Bezier& aOuterSectionBezier, const Bezier& aInnerSectionBezier) : outerSectionBezier(aOuterSectionBezier), innerSectionBezier(aInnerSectionBezier) {} }; // aCornerDim.width // |<----------------->| // | | // --+-------------___---+-- // ^ | __-- | ^ // | | _- | | // | | / | | aBorderWidthH // | | / | | // | | | | v // | | | __--+-- // aCornerDim.height | || _- // | || / // | | / // | | | // | | | // | | | // | | | // v | | // --+---------+ // | | // |<------->| // aBorderWidthV DashedCornerFinder(const Bezier& aOuterBezier, const Bezier& aInnerBezier, Float aBorderWidthH, Float aBorderWidthV, const Size& aCornerDim); bool HasMore(void) const; Result Next(void); private: static const size_t MAX_LOOP = 32; // Bezier control points for the outer curve and the inner curve. // // ___---+ outer curve // __-- | // _- | // / | // / | // | | // | __--+ inner curve // | _- // | / // | / // | | // | | // | | // | | // | | // +---------+ Bezier mOuterBezier; Bezier mInnerBezier; Point mLastOuterP; Point mLastInnerP; Float mLastOuterT; Float mLastInnerT; // Length for each segment, ratio of the border width at that point. Float mBestDashLength; // If one of border-widths is 0, do not calculate mBestDashLength, and draw // segments until it reaches the other side or exceeds mMaxCount. bool mHasZeroBorderWidth; bool mHasMore; // The maximum number of segments. size_t mMaxCount; enum { // radius.width // |<----------------->| // | | // --+-------------___---+-- // ^ | __-- | ^ // | | _- | | // | | / + | top-width // | | / | | // | | | | v // | | | __--+-- // radius.height | || _- // | || / // | | / // | | | // | | | // | | | // | | | // v | | // --+----+----+ // | | // |<------->| // left-width // * top-width == left-width // * radius.width == radius.height // * top-width < radius.width * 2 // // Split the perfect circle's arc into 2n segments, each segment's length is // top-width * dashLength. Then split the inner curve and the outer curve // with same angles. // // radius.width // |<---------------------->| // | | v // --+------------------------+-- // ^ | | | top-width / 2 // | | perfect | | // | | circle's ___---+-- // | | arc __-+ | ^ // | | | _- | | // radius.height | | | + | +-- // | | | / \ | | // | | | | \ | | // | | | | \ | | // | | +->| \ | | // | | +---__ \ | | // | | | --__ \ | | // | | | ---__ \ | | // v | | --_\|| // --+----+----+--------------+ // | | | // |<-->| | // left-width / 2 PERFECT, // Other cases. // // Split the outer curve and the inner curve into 2n segments, each segment // satisfies following: // (OuterL_i + InnerL_i) / 2 == dashLength * (W_i + W_{i-1}) / 2 OTHER } mType; size_t mI; size_t mCount; // Determine mType from parameters. void DetermineType(Float aBorderWidthH, Float aBorderWidthV); // Reset calculation. void Reset(void); // Find next segment. Float FindNext(Float dashLength); // Find mBestDashLength for parameters. void FindBestDashLength(Float aMinBorderWidth, Float aMaxBorderWidth, Float aMinBorderRadius, Float aMaxBorderRadius); // Fill corner with dashes with given dash length, and return the number of // segments and last segment's dash length. bool GetCountAndLastDashLength(Float aDashLength, size_t* aCount, Float* aActualDashLength); }; } // namespace mozilla #endif /* mozilla_DashedCornerFinder_h_ */