Home | History | Annotate | Download | only in minikin
      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:
     35     Run(const Range& range) : mRange(range) {}
     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.
     59     virtual const MinikinPaint* getPaint() const { return nullptr; }
     60 
     61     // Measures the hyphenation piece and fills each character's advances and overhangs.
     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 
     70     inline const Range& getRange() const { return mRange; }
     71 
     72 protected:
     73     const Range mRange;
     74 };
     75 
     76 class StyleRun : public Run {
     77 public:
     78     StyleRun(const Range& range, MinikinPaint&& paint, bool isRtl)
     79             : Run(range), mPaint(std::move(paint)), mIsRtl(isRtl) {}
     80 
     81     bool canHyphenate() const override { return true; }
     82     uint32_t getLocaleListId() const override { return mPaint.localeListId; }
     83     bool isRtl() const override { return mIsRtl; }
     84 
     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 
     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 
     98     const MinikinPaint* getPaint() const override { return &mPaint; }
     99 
    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:
    115     ReplacementRun(const Range& range, float width, uint32_t localeListId)
    116             : Run(range), mWidth(width), mLocaleListId(localeListId) {}
    117 
    118     bool isRtl() const { return false; }
    119     bool canHyphenate() const { return false; }
    120     uint32_t getLocaleListId() const { return mLocaleListId; }
    121 
    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 
    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 
    154     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 
    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.
    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:
    207     MeasuredTextBuilder() {}
    208 
    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 
    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>
    219     void addCustomRun(Args&&... args) {
    220         mRuns.emplace_back(std::make_unique<T>(std::forward<Args>(args)...));
    221     }
    222 
    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