diff options
Diffstat (limited to 'layout/painting/DashedCornerFinder.h')
-rw-r--r-- | layout/painting/DashedCornerFinder.h | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/layout/painting/DashedCornerFinder.h b/layout/painting/DashedCornerFinder.h new file mode 100644 index 0000000000..3a409d19f7 --- /dev/null +++ b/layout/painting/DashedCornerFinder.h @@ -0,0 +1,274 @@ +/* -*- 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_ */ |