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/LineBreakStyle.h" 27 #include "minikin/Macros.h" 28 #include "minikin/MinikinFont.h" 29 #include "minikin/Range.h" 30 #include "minikin/U16StringPiece.h" 31 32 namespace minikin { 33 34 class Run { 35 public: Run(const Range & range)36 Run(const Range& range) : mRange(range) {} ~Run()37 virtual ~Run() {} 38 39 // Returns true if this run is RTL. Otherwise returns false. 40 virtual bool isRtl() const = 0; 41 42 // Returns true if this run can be broken into multiple pieces for line breaking. 43 virtual bool canBreak() const = 0; 44 45 // Return the line break style(lb) for this run. 46 virtual LineBreakStyle lineBreakStyle() const = 0; 47 48 // Return the line break word style(lw) for this run. 49 virtual LineBreakWordStyle lineBreakWordStyle() const = 0; 50 51 // Returns the locale list ID for this run. 52 virtual uint32_t getLocaleListId() const = 0; 53 54 // Fills the each character's advances, extents and overhangs. 55 virtual void getMetrics(const U16StringPiece& text, std::vector<float>* advances, 56 LayoutPieces* precomputed, LayoutPieces* outPieces) const = 0; 57 58 virtual std::pair<float, MinikinRect> getBounds(const U16StringPiece& text, const Range& range, 59 const LayoutPieces& pieces) const = 0; 60 virtual MinikinExtent getExtent(const U16StringPiece& text, const Range& range, 61 const LayoutPieces& pieces) const = 0; 62 63 virtual void appendLayout(const U16StringPiece& text, const Range& range, 64 const Range& contextRange, const LayoutPieces& pieces, 65 const MinikinPaint& paint, uint32_t outOrigin, 66 StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, 67 Layout* outLayout) const = 0; 68 69 virtual float measureText(const U16StringPiece& text) const = 0; 70 71 // Following two methods are only called when the implementation returns true for 72 // canBreak method. 73 74 // Returns the paint pointer used for this run. 75 // Returns null if canBreak has not returned true. getPaint()76 virtual const MinikinPaint* getPaint() const { return nullptr; } 77 78 // Measures the hyphenation piece and fills each character's advances and overhangs. measureHyphenPiece(const U16StringPiece &,const Range &,StartHyphenEdit,EndHyphenEdit,LayoutPieces *)79 virtual float measureHyphenPiece(const U16StringPiece& /* text */, 80 const Range& /* hyphenPieceRange */, 81 StartHyphenEdit /* startHyphen */, 82 EndHyphenEdit /* endHyphen */, 83 LayoutPieces* /* pieces */) const { 84 return 0.0; 85 } 86 getRange()87 inline const Range& getRange() const { return mRange; } 88 89 protected: 90 const Range mRange; 91 }; 92 93 class StyleRun : public Run { 94 public: StyleRun(const Range & range,MinikinPaint && paint,int lineBreakStyle,int lineBreakWordStyle,bool isRtl)95 StyleRun(const Range& range, MinikinPaint&& paint, int lineBreakStyle, int lineBreakWordStyle, 96 bool isRtl) 97 : Run(range), 98 mPaint(std::move(paint)), 99 mLineBreakStyle(lineBreakStyle), 100 mLineBreakWordStyle(lineBreakWordStyle), 101 mIsRtl(isRtl) {} 102 canBreak()103 bool canBreak() const override { return true; } lineBreakStyle()104 LineBreakStyle lineBreakStyle() const override { 105 return static_cast<LineBreakStyle>(mLineBreakStyle); 106 } lineBreakWordStyle()107 LineBreakWordStyle lineBreakWordStyle() const override { 108 return static_cast<LineBreakWordStyle>(mLineBreakWordStyle); 109 } getLocaleListId()110 uint32_t getLocaleListId() const override { return mPaint.localeListId; } isRtl()111 bool isRtl() const override { return mIsRtl; } 112 113 void getMetrics(const U16StringPiece& text, std::vector<float>* advances, 114 LayoutPieces* precomputed, LayoutPieces* outPieces) const override; 115 116 std::pair<float, MinikinRect> getBounds(const U16StringPiece& text, const Range& range, 117 const LayoutPieces& pieces) const override; 118 119 MinikinExtent getExtent(const U16StringPiece& text, const Range& range, 120 const LayoutPieces& pieces) const override; 121 122 void appendLayout(const U16StringPiece& text, const Range& range, const Range& contextRange, 123 const LayoutPieces& pieces, const MinikinPaint& paint, uint32_t outOrigin, 124 StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, 125 Layout* outLayout) const override; 126 getPaint()127 const MinikinPaint* getPaint() const override { return &mPaint; } 128 129 float measureHyphenPiece(const U16StringPiece& text, const Range& range, 130 StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, 131 LayoutPieces* pieces) const override; 132 float measureText(const U16StringPiece& text) const; 133 134 private: 135 MinikinPaint mPaint; 136 int mLineBreakStyle; 137 int mLineBreakWordStyle; 138 const bool mIsRtl; 139 }; 140 141 class ReplacementRun : public Run { 142 public: ReplacementRun(const Range & range,float width,uint32_t localeListId)143 ReplacementRun(const Range& range, float width, uint32_t localeListId) 144 : Run(range), mWidth(width), mLocaleListId(localeListId) {} 145 isRtl()146 bool isRtl() const { return false; } canBreak()147 bool canBreak() const { return false; } lineBreakStyle()148 LineBreakStyle lineBreakStyle() const override { return LineBreakStyle::None; } lineBreakWordStyle()149 LineBreakWordStyle lineBreakWordStyle() const override { return LineBreakWordStyle::None; } getLocaleListId()150 uint32_t getLocaleListId() const { return mLocaleListId; } 151 getMetrics(const U16StringPiece &,std::vector<float> * advances,LayoutPieces *,LayoutPieces *)152 void getMetrics(const U16StringPiece& /* text */, std::vector<float>* advances, 153 LayoutPieces* /* precomputed */, LayoutPieces* /* outPieces */) const override { 154 (*advances)[mRange.getStart()] = mWidth; 155 // TODO: Get the extents information from the caller. 156 } 157 getBounds(const U16StringPiece &,const Range &,const LayoutPieces &)158 std::pair<float, MinikinRect> getBounds(const U16StringPiece& /* text */, 159 const Range& /* range */, 160 const LayoutPieces& /* pieces */) const override { 161 // Bounding Box is not used in replacement run. 162 return std::make_pair(mWidth, MinikinRect()); 163 } 164 getExtent(const U16StringPiece &,const Range &,const LayoutPieces &)165 MinikinExtent getExtent(const U16StringPiece& /* text */, const Range& /* range */, 166 const LayoutPieces& /* pieces */) const override { 167 return MinikinExtent(); 168 } 169 appendLayout(const U16StringPiece &,const Range &,const Range &,const LayoutPieces &,const MinikinPaint &,uint32_t,StartHyphenEdit,EndHyphenEdit,Layout *)170 void appendLayout(const U16StringPiece& /* text */, const Range& /* range */, 171 const Range& /* contextRange */, const LayoutPieces& /* pieces */, 172 const MinikinPaint& /* paint */, uint32_t /* outOrigin */, 173 StartHyphenEdit /* startHyphen */, EndHyphenEdit /* endHyphen */, 174 Layout* /* outLayout*/) const override {} 175 measureText(const U16StringPiece &)176 float measureText(const U16StringPiece&) const { return 0; } 177 178 private: 179 const float mWidth; 180 const uint32_t mLocaleListId; 181 }; 182 183 // Represents a hyphenation break point. 184 struct HyphenBreak { 185 // The break offset. 186 uint32_t offset; 187 188 // The hyphenation type. 189 HyphenationType type; 190 191 // The width of preceding piece after break at hyphenation point. 192 float first; 193 194 // The width of following piece after break at hyphenation point. 195 float second; 196 HyphenBreakHyphenBreak197 HyphenBreak(uint32_t offset, HyphenationType type, float first, float second) 198 : offset(offset), type(type), first(first), second(second) {} 199 }; 200 201 class MeasuredText { 202 public: 203 // Character widths. 204 std::vector<float> widths; 205 206 // Hyphenation points. 207 std::vector<HyphenBreak> hyphenBreaks; 208 209 // The style information. 210 std::vector<std::unique_ptr<Run>> runs; 211 212 // The copied layout pieces for construcing final layouts. 213 // TODO: Stop assigning width/extents if layout pieces are available for reducing memory impact. 214 LayoutPieces layoutPieces; 215 getMemoryUsage()216 uint32_t getMemoryUsage() const { 217 return sizeof(float) * widths.size() + sizeof(HyphenBreak) * hyphenBreaks.size() + 218 layoutPieces.getMemoryUsage(); 219 } 220 221 Layout buildLayout(const U16StringPiece& textBuf, const Range& range, const Range& contextRange, 222 const MinikinPaint& paint, StartHyphenEdit startHyphen, 223 EndHyphenEdit endHyphen); 224 MinikinRect getBounds(const U16StringPiece& textBuf, const Range& range) const; 225 MinikinExtent getExtent(const U16StringPiece& textBuf, const Range& range) const; 226 227 MeasuredText(MeasuredText&&) = default; 228 MeasuredText& operator=(MeasuredText&&) = default; 229 230 MINIKIN_PREVENT_COPY_AND_ASSIGN(MeasuredText); 231 232 private: 233 friend class MeasuredTextBuilder; 234 235 void measure(const U16StringPiece& textBuf, bool computeHyphenation, bool computeLayout, 236 bool ignoreHyphenKerning, MeasuredText* hint); 237 238 // Use MeasuredTextBuilder instead. MeasuredText(const U16StringPiece & textBuf,std::vector<std::unique_ptr<Run>> && runs,bool computeHyphenation,bool computeLayout,bool ignoreHyphenKerning,MeasuredText * hint)239 MeasuredText(const U16StringPiece& textBuf, std::vector<std::unique_ptr<Run>>&& runs, 240 bool computeHyphenation, bool computeLayout, bool ignoreHyphenKerning, 241 MeasuredText* hint) 242 : widths(textBuf.size()), runs(std::move(runs)) { 243 measure(textBuf, computeHyphenation, computeLayout, ignoreHyphenKerning, hint); 244 } 245 }; 246 247 class MeasuredTextBuilder { 248 public: MeasuredTextBuilder()249 MeasuredTextBuilder() {} 250 addStyleRun(int32_t start,int32_t end,MinikinPaint && paint,int lineBreakStyle,int lineBreakWordStyle,bool isRtl)251 void addStyleRun(int32_t start, int32_t end, MinikinPaint&& paint, int lineBreakStyle, 252 int lineBreakWordStyle, bool isRtl) { 253 mRuns.emplace_back(std::make_unique<StyleRun>(Range(start, end), std::move(paint), 254 lineBreakStyle, lineBreakWordStyle, isRtl)); 255 } 256 addReplacementRun(int32_t start,int32_t end,float width,uint32_t localeListId)257 void addReplacementRun(int32_t start, int32_t end, float width, uint32_t localeListId) { 258 mRuns.emplace_back( 259 std::make_unique<ReplacementRun>(Range(start, end), width, localeListId)); 260 } 261 262 template <class T, typename... Args> addCustomRun(Args &&...args)263 void addCustomRun(Args&&... args) { 264 mRuns.emplace_back(std::make_unique<T>(std::forward<Args>(args)...)); 265 } 266 build(const U16StringPiece & textBuf,bool computeHyphenation,bool computeLayout,bool ignoreHyphenKerning,MeasuredText * hint)267 std::unique_ptr<MeasuredText> build(const U16StringPiece& textBuf, bool computeHyphenation, 268 bool computeLayout, bool ignoreHyphenKerning, 269 MeasuredText* hint) { 270 // Unable to use make_unique here since make_unique is not a friend of MeasuredText. 271 return std::unique_ptr<MeasuredText>(new MeasuredText(textBuf, std::move(mRuns), 272 computeHyphenation, computeLayout, 273 ignoreHyphenKerning, hint)); 274 } 275 276 MINIKIN_PREVENT_COPY_ASSIGN_AND_MOVE(MeasuredTextBuilder); 277 278 private: 279 std::vector<std::unique_ptr<Run>> mRuns; 280 }; 281 282 } // namespace minikin 283 284 #endif // MINIKIN_MEASURED_TEXT_H 285