| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef MINIKIN_MEASURED_TEXT_H |
| #define MINIKIN_MEASURED_TEXT_H |
| |
| #include <deque> |
| #include <vector> |
| |
| #include "minikin/FontCollection.h" |
| #include "minikin/Layout.h" |
| #include "minikin/Macros.h" |
| #include "minikin/MinikinFont.h" |
| #include "minikin/Range.h" |
| #include "minikin/U16StringPiece.h" |
| |
| namespace minikin { |
| |
| class Run { |
| public: |
| Run(const Range& range) : mRange(range) {} |
| virtual ~Run() {} |
| |
| // Returns true if this run is RTL. Otherwise returns false. |
| virtual bool isRtl() const = 0; |
| |
| // Returns true if this run is a target of hyphenation. Otherwise return false. |
| virtual bool canHyphenate() const = 0; |
| |
| // Returns the locale list ID for this run. |
| virtual uint32_t getLocaleListId() const = 0; |
| |
| // Fills the each character's advances, extents and overhangs. |
| virtual void getMetrics(const U16StringPiece& text, float* advances, MinikinExtent* extents, |
| LayoutPieces* piece) const = 0; |
| |
| // Following two methods are only called when the implementation returns true for |
| // canHyphenate method. |
| |
| // Returns the paint pointer used for this run. |
| // Returns null if canHyphenate has not returned true. |
| virtual const MinikinPaint* getPaint() const { return nullptr; } |
| |
| // Measures the hyphenation piece and fills each character's advances and overhangs. |
| virtual float measureHyphenPiece(const U16StringPiece& /* text */, |
| const Range& /* hyphenPieceRange */, |
| StartHyphenEdit /* startHyphen */, |
| EndHyphenEdit /* endHyphen */, float* /* advances */, |
| LayoutPieces* /* pieces */) const { |
| return 0.0; |
| } |
| |
| inline const Range& getRange() const { return mRange; } |
| |
| protected: |
| const Range mRange; |
| }; |
| |
| class StyleRun : public Run { |
| public: |
| StyleRun(const Range& range, MinikinPaint&& paint, bool isRtl) |
| : Run(range), mPaint(std::move(paint)), mIsRtl(isRtl) {} |
| |
| bool canHyphenate() const override { return true; } |
| uint32_t getLocaleListId() const override { return mPaint.localeListId; } |
| bool isRtl() const override { return mIsRtl; } |
| |
| void getMetrics(const U16StringPiece& text, float* advances, MinikinExtent* extents, |
| LayoutPieces* pieces) const override { |
| Bidi bidiFlag = mIsRtl ? Bidi::FORCE_RTL : Bidi::FORCE_LTR; |
| Layout::measureText(text, mRange, bidiFlag, mPaint, StartHyphenEdit::NO_EDIT, |
| EndHyphenEdit::NO_EDIT, advances, extents, pieces); |
| } |
| |
| const MinikinPaint* getPaint() const override { return &mPaint; } |
| |
| float measureHyphenPiece(const U16StringPiece& text, const Range& range, |
| StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, float* advances, |
| LayoutPieces* pieces) const override { |
| Bidi bidiFlag = mIsRtl ? Bidi::FORCE_RTL : Bidi::FORCE_LTR; |
| return Layout::measureText(text, range, bidiFlag, mPaint, startHyphen, endHyphen, advances, |
| nullptr /* extent */, pieces); |
| } |
| |
| private: |
| MinikinPaint mPaint; |
| const bool mIsRtl; |
| }; |
| |
| class ReplacementRun : public Run { |
| public: |
| ReplacementRun(const Range& range, float width, uint32_t localeListId) |
| : Run(range), mWidth(width), mLocaleListId(localeListId) {} |
| |
| bool isRtl() const { return false; } |
| bool canHyphenate() const { return false; } |
| uint32_t getLocaleListId() const { return mLocaleListId; } |
| |
| void getMetrics(const U16StringPiece& /* unused */, float* advances, |
| MinikinExtent* /* unused */, LayoutPieces* /* pieces */) const override { |
| advances[0] = mWidth; |
| // TODO: Get the extents information from the caller. |
| } |
| |
| private: |
| const float mWidth; |
| const uint32_t mLocaleListId; |
| }; |
| |
| // Represents a hyphenation break point. |
| struct HyphenBreak { |
| // The break offset. |
| uint32_t offset; |
| |
| // The hyphenation type. |
| HyphenationType type; |
| |
| // The width of preceding piece after break at hyphenation point. |
| float first; |
| |
| // The width of following piece after break at hyphenation point. |
| float second; |
| |
| HyphenBreak(uint32_t offset, HyphenationType type, float first, float second) |
| : offset(offset), type(type), first(first), second(second) {} |
| }; |
| |
| class MeasuredText { |
| public: |
| // Character widths. |
| std::vector<float> widths; |
| |
| // Font vertical extents for characters. |
| // TODO: Introduce compression for extents. Usually, this has the same values for all chars. |
| std::vector<MinikinExtent> extents; |
| |
| // Hyphenation points. |
| std::vector<HyphenBreak> hyphenBreaks; |
| |
| // The style information. |
| std::vector<std::unique_ptr<Run>> runs; |
| |
| // The copied layout pieces for construcing final layouts. |
| // TODO: Stop assigning width/extents if layout pieces are available for reducing memory impact. |
| LayoutPieces layoutPieces; |
| |
| uint32_t getMemoryUsage() const { |
| return sizeof(float) * widths.size() + sizeof(MinikinExtent) * extents.size() + |
| sizeof(HyphenBreak) * hyphenBreaks.size() + layoutPieces.getMemoryUsage(); |
| } |
| |
| void buildLayout(const U16StringPiece& textBuf, const Range& range, const MinikinPaint& paint, |
| Bidi bidiFlag, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, |
| Layout* layout); |
| |
| MeasuredText(MeasuredText&&) = default; |
| MeasuredText& operator=(MeasuredText&&) = default; |
| |
| MINIKIN_PREVENT_COPY_AND_ASSIGN(MeasuredText); |
| |
| private: |
| friend class MeasuredTextBuilder; |
| |
| void measure(const U16StringPiece& textBuf, bool computeHyphenation, bool computeLayout); |
| |
| // Use MeasuredTextBuilder instead. |
| MeasuredText(const U16StringPiece& textBuf, std::vector<std::unique_ptr<Run>>&& runs, |
| bool computeHyphenation, bool computeLayout) |
| : widths(textBuf.size()), extents(textBuf.size()), runs(std::move(runs)) { |
| measure(textBuf, computeHyphenation, computeLayout); |
| } |
| }; |
| |
| class MeasuredTextBuilder { |
| public: |
| MeasuredTextBuilder() {} |
| |
| void addStyleRun(int32_t start, int32_t end, MinikinPaint&& paint, bool isRtl) { |
| mRuns.emplace_back(std::make_unique<StyleRun>(Range(start, end), std::move(paint), isRtl)); |
| } |
| |
| void addReplacementRun(int32_t start, int32_t end, float width, uint32_t localeListId) { |
| mRuns.emplace_back( |
| std::make_unique<ReplacementRun>(Range(start, end), width, localeListId)); |
| } |
| |
| template <class T, typename... Args> |
| void addCustomRun(Args&&... args) { |
| mRuns.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)); |
| } |
| |
| std::unique_ptr<MeasuredText> build(const U16StringPiece& textBuf, bool computeHyphenation, |
| bool computeLayout) { |
| // Unable to use make_unique here since make_unique is not a friend of MeasuredText. |
| return std::unique_ptr<MeasuredText>( |
| new MeasuredText(textBuf, std::move(mRuns), computeHyphenation, computeLayout)); |
| } |
| |
| MINIKIN_PREVENT_COPY_ASSIGN_AND_MOVE(MeasuredTextBuilder); |
| |
| private: |
| std::vector<std::unique_ptr<Run>> mRuns; |
| }; |
| |
| } // namespace minikin |
| |
| #endif // MINIKIN_MEASURED_TEXT_H |