1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef MINIKIN_MEASURED_TEXT_H 18 #define MINIKIN_MEASURED_TEXT_H 19 20 #include <deque> 21 #include <vector> 22 23 #include "minikin/FontCollection.h" 24 #include "minikin/Layout.h" 25 #include "minikin/LayoutPieces.h" 26 #include "minikin/Macros.h" 27 #include "minikin/MinikinFont.h" 28 #include "minikin/Range.h" 29 #include "minikin/U16StringPiece.h" 30 31 namespace minikin { 32 33 class Run { 34 public: Run(const Range & range)35 Run(const Range& range) : mRange(range) {} ~Run()36 virtual ~Run() {} 37 38 // Returns true if this run is RTL. Otherwise returns false. 39 virtual bool isRtl() const = 0; 40 41 // Returns true if this run is a target of hyphenation. Otherwise return false. 42 virtual bool canHyphenate() const = 0; 43 44 // Returns the locale list ID for this run. 45 virtual uint32_t getLocaleListId() const = 0; 46 47 // Fills the each character's advances, extents and overhangs. 48 virtual void getMetrics(const U16StringPiece& text, float* advances, MinikinExtent* extents, 49 LayoutPieces* piece) const = 0; 50 51 virtual std::pair<float, MinikinRect> getBounds(const U16StringPiece& text, const Range& range, 52 const LayoutPieces& pieces) const = 0; 53 54 // Following two methods are only called when the implementation returns true for 55 // canHyphenate method. 56 57 // Returns the paint pointer used for this run. 58 // Returns null if canHyphenate has not returned true. getPaint()59 virtual const MinikinPaint* getPaint() const { return nullptr; } 60 61 // Measures the hyphenation piece and fills each character's advances and overhangs. measureHyphenPiece(const U16StringPiece &,const Range &,StartHyphenEdit,EndHyphenEdit,float *,LayoutPieces *)62 virtual float measureHyphenPiece(const U16StringPiece& /* text */, 63 const Range& /* hyphenPieceRange */, 64 StartHyphenEdit /* startHyphen */, 65 EndHyphenEdit /* endHyphen */, float* /* advances */, 66 LayoutPieces* /* pieces */) const { 67 return 0.0; 68 } 69 getRange()70 inline const Range& getRange() const { return mRange; } 71 72 protected: 73 const Range mRange; 74 }; 75 76 class StyleRun : public Run { 77 public: StyleRun(const Range & range,MinikinPaint && paint,bool isRtl)78 StyleRun(const Range& range, MinikinPaint&& paint, bool isRtl) 79 : Run(range), mPaint(std::move(paint)), mIsRtl(isRtl) {} 80 canHyphenate()81 bool canHyphenate() const override { return true; } getLocaleListId()82 uint32_t getLocaleListId() const override { return mPaint.localeListId; } isRtl()83 bool isRtl() const override { return mIsRtl; } 84 getMetrics(const U16StringPiece & text,float * advances,MinikinExtent * extents,LayoutPieces * pieces)85 void getMetrics(const U16StringPiece& text, float* advances, MinikinExtent* extents, 86 LayoutPieces* pieces) const override { 87 Bidi bidiFlag = mIsRtl ? Bidi::FORCE_RTL : Bidi::FORCE_LTR; 88 Layout::measureText(text, mRange, bidiFlag, mPaint, StartHyphenEdit::NO_EDIT, 89 EndHyphenEdit::NO_EDIT, advances, extents, pieces); 90 } 91 getBounds(const U16StringPiece & text,const Range & range,const LayoutPieces & pieces)92 std::pair<float, MinikinRect> getBounds(const U16StringPiece& text, const Range& range, 93 const LayoutPieces& pieces) const override { 94 Bidi bidiFlag = mIsRtl ? Bidi::FORCE_RTL : Bidi::FORCE_LTR; 95 return Layout::getBoundsWithPrecomputedPieces(text, range, bidiFlag, mPaint, pieces); 96 } 97 getPaint()98 const MinikinPaint* getPaint() const override { return &mPaint; } 99 measureHyphenPiece(const U16StringPiece & text,const Range & range,StartHyphenEdit startHyphen,EndHyphenEdit endHyphen,float * advances,LayoutPieces * pieces)100 float measureHyphenPiece(const U16StringPiece& text, const Range& range, 101 StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, float* advances, 102 LayoutPieces* pieces) const override { 103 Bidi bidiFlag = mIsRtl ? Bidi::FORCE_RTL : Bidi::FORCE_LTR; 104 return Layout::measureText(text, range, bidiFlag, mPaint, startHyphen, endHyphen, advances, 105 nullptr /* extent */, pieces); 106 } 107 108 private: 109 MinikinPaint mPaint; 110 const bool mIsRtl; 111 }; 112 113 class ReplacementRun : public Run { 114 public: ReplacementRun(const Range & range,float width,uint32_t localeListId)115 ReplacementRun(const Range& range, float width, uint32_t localeListId) 116 : Run(range), mWidth(width), mLocaleListId(localeListId) {} 117 isRtl()118 bool isRtl() const { return false; } canHyphenate()119 bool canHyphenate() const { return false; } getLocaleListId()120 uint32_t getLocaleListId() const { return mLocaleListId; } 121 getMetrics(const U16StringPiece &,float * advances,MinikinExtent *,LayoutPieces *)122 void getMetrics(const U16StringPiece& /* unused */, float* advances, 123 MinikinExtent* /* unused */, LayoutPieces* /* pieces */) const override { 124 advances[0] = mWidth; 125 // TODO: Get the extents information from the caller. 126 } 127 getBounds(const U16StringPiece &,const Range &,const LayoutPieces &)128 std::pair<float, MinikinRect> getBounds(const U16StringPiece& /* text */, 129 const Range& /* range */, 130 const LayoutPieces& /* pieces */) const override { 131 // Bounding Box is not used in replacement run. 132 return std::make_pair(mWidth, MinikinRect()); 133 } 134 135 private: 136 const float mWidth; 137 const uint32_t mLocaleListId; 138 }; 139 140 // Represents a hyphenation break point. 141 struct HyphenBreak { 142 // The break offset. 143 uint32_t offset; 144 145 // The hyphenation type. 146 HyphenationType type; 147 148 // The width of preceding piece after break at hyphenation point. 149 float first; 150 151 // The width of following piece after break at hyphenation point. 152 float second; 153 HyphenBreakHyphenBreak154 HyphenBreak(uint32_t offset, HyphenationType type, float first, float second) 155 : offset(offset), type(type), first(first), second(second) {} 156 }; 157 158 class MeasuredText { 159 public: 160 // Character widths. 161 std::vector<float> widths; 162 163 // Font vertical extents for characters. 164 // TODO: Introduce compression for extents. Usually, this has the same values for all chars. 165 std::vector<MinikinExtent> extents; 166 167 // Hyphenation points. 168 std::vector<HyphenBreak> hyphenBreaks; 169 170 // The style information. 171 std::vector<std::unique_ptr<Run>> runs; 172 173 // The copied layout pieces for construcing final layouts. 174 // TODO: Stop assigning width/extents if layout pieces are available for reducing memory impact. 175 LayoutPieces layoutPieces; 176 getMemoryUsage()177 uint32_t getMemoryUsage() const { 178 return sizeof(float) * widths.size() + sizeof(MinikinExtent) * extents.size() + 179 sizeof(HyphenBreak) * hyphenBreaks.size() + layoutPieces.getMemoryUsage(); 180 } 181 182 void buildLayout(const U16StringPiece& textBuf, const Range& range, const MinikinPaint& paint, 183 Bidi bidiFlag, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, 184 Layout* layout); 185 MinikinRect getBounds(const U16StringPiece& textBuf, const Range& range); 186 187 MeasuredText(MeasuredText&&) = default; 188 MeasuredText& operator=(MeasuredText&&) = default; 189 190 MINIKIN_PREVENT_COPY_AND_ASSIGN(MeasuredText); 191 192 private: 193 friend class MeasuredTextBuilder; 194 195 void measure(const U16StringPiece& textBuf, bool computeHyphenation, bool computeLayout); 196 197 // Use MeasuredTextBuilder instead. MeasuredText(const U16StringPiece & textBuf,std::vector<std::unique_ptr<Run>> && runs,bool computeHyphenation,bool computeLayout)198 MeasuredText(const U16StringPiece& textBuf, std::vector<std::unique_ptr<Run>>&& runs, 199 bool computeHyphenation, bool computeLayout) 200 : widths(textBuf.size()), extents(textBuf.size()), runs(std::move(runs)) { 201 measure(textBuf, computeHyphenation, computeLayout); 202 } 203 }; 204 205 class MeasuredTextBuilder { 206 public: MeasuredTextBuilder()207 MeasuredTextBuilder() {} 208 addStyleRun(int32_t start,int32_t end,MinikinPaint && paint,bool isRtl)209 void addStyleRun(int32_t start, int32_t end, MinikinPaint&& paint, bool isRtl) { 210 mRuns.emplace_back(std::make_unique<StyleRun>(Range(start, end), std::move(paint), isRtl)); 211 } 212 addReplacementRun(int32_t start,int32_t end,float width,uint32_t localeListId)213 void addReplacementRun(int32_t start, int32_t end, float width, uint32_t localeListId) { 214 mRuns.emplace_back( 215 std::make_unique<ReplacementRun>(Range(start, end), width, localeListId)); 216 } 217 218 template <class T, typename... Args> addCustomRun(Args &&...args)219 void addCustomRun(Args&&... args) { 220 mRuns.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)); 221 } 222 build(const U16StringPiece & textBuf,bool computeHyphenation,bool computeLayout)223 std::unique_ptr<MeasuredText> build(const U16StringPiece& textBuf, bool computeHyphenation, 224 bool computeLayout) { 225 // Unable to use make_unique here since make_unique is not a friend of MeasuredText. 226 return std::unique_ptr<MeasuredText>( 227 new MeasuredText(textBuf, std::move(mRuns), computeHyphenation, computeLayout)); 228 } 229 230 MINIKIN_PREVENT_COPY_ASSIGN_AND_MOVE(MeasuredTextBuilder); 231 232 private: 233 std::vector<std::unique_ptr<Run>> mRuns; 234 }; 235 236 } // namespace minikin 237 238 #endif // MINIKIN_MEASURED_TEXT_H 239