Home | History | Annotate | Download | only in minikin
      1 /*
      2  * Copyright (C) 2013 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_LAYOUT_H
     18 #define MINIKIN_LAYOUT_H
     19 
     20 #include <memory>
     21 #include <unordered_map>
     22 #include <vector>
     23 
     24 #include <gtest/gtest_prod.h>
     25 #include <utils/JenkinsHash.h>
     26 
     27 #include "minikin/FontCollection.h"
     28 #include "minikin/Range.h"
     29 #include "minikin/U16StringPiece.h"
     30 
     31 namespace minikin {
     32 
     33 class Layout;
     34 struct LayoutPieces;
     35 
     36 struct LayoutGlyph {
     37     // index into mFaces and mHbFonts vectors. We could imagine
     38     // moving this into a run length representation, because it's
     39     // more efficient for long strings, and we'll probably need
     40     // something like that for paint attributes (color, underline,
     41     // fake b/i, etc), as having those per-glyph is bloated.
     42     int font_ix;
     43 
     44     unsigned int glyph_id;
     45     float x;
     46     float y;
     47 };
     48 
     49 // Must be the same value with Paint.java
     50 enum class Bidi : uint8_t {
     51     LTR = 0b0000,          // Must be same with Paint.BIDI_LTR
     52     RTL = 0b0001,          // Must be same with Paint.BIDI_RTL
     53     DEFAULT_LTR = 0b0010,  // Must be same with Paint.BIDI_DEFAULT_LTR
     54     DEFAULT_RTL = 0b0011,  // Must be same with Paint.BIDI_DEFAULT_RTL
     55     FORCE_LTR = 0b0100,    // Must be same with Paint.BIDI_FORCE_LTR
     56     FORCE_RTL = 0b0101,    // Must be same with Paint.BIDI_FORCE_RTL
     57 };
     58 
     59 inline bool isRtl(Bidi bidi) {
     60     return static_cast<uint8_t>(bidi) & 0b0001;
     61 }
     62 inline bool isOverride(Bidi bidi) {
     63     return static_cast<uint8_t>(bidi) & 0b0100;
     64 }
     65 
     66 // Lifecycle and threading assumptions for Layout:
     67 // The object is assumed to be owned by a single thread; multiple threads
     68 // may not mutate it at the same time.
     69 class Layout {
     70 public:
     71     Layout()
     72             : mGlyphs(),
     73               mAdvances(),
     74               mExtents(),
     75               mFaces(),
     76               mAdvance(0),
     77               mBounds() {
     78         mBounds.setEmpty();
     79     }
     80 
     81     Layout(Layout&& layout) = default;
     82 
     83     Layout(const Layout&) = default;
     84     Layout& operator=(const Layout&) = default;
     85 
     86     void dump() const;
     87 
     88     void doLayout(const U16StringPiece& str, const Range& range, Bidi bidiFlags,
     89                   const MinikinPaint& paint, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen);
     90 
     91     void doLayoutWithPrecomputedPieces(const U16StringPiece& str, const Range& range,
     92                                        Bidi bidiFlags, const MinikinPaint& paint,
     93                                        StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
     94                                        const LayoutPieces& pieces);
     95     static std::pair<float, MinikinRect> getBoundsWithPrecomputedPieces(const U16StringPiece& str,
     96                                                                         const Range& range,
     97                                                                         Bidi bidiFlags,
     98                                                                         const MinikinPaint& paint,
     99                                                                         const LayoutPieces& pieces);
    100 
    101     static float measureText(const U16StringPiece& str, const Range& range, Bidi bidiFlags,
    102                              const MinikinPaint& paint, StartHyphenEdit startHyphen,
    103                              EndHyphenEdit endHyphen, float* advances, MinikinExtent* extents,
    104                              LayoutPieces* pieces);
    105 
    106     inline const std::vector<float>& advances() const { return mAdvances; }
    107 
    108     // public accessors
    109     size_t nGlyphs() const;
    110     const MinikinFont* getFont(int i) const;
    111     FontFakery getFakery(int i) const;
    112     unsigned int getGlyphId(int i) const;
    113     float getX(int i) const;
    114     float getY(int i) const;
    115 
    116     float getAdvance() const;
    117 
    118     // Get advances, copying into caller-provided buffer. The size of this
    119     // buffer must match the length of the string (count arg to doLayout).
    120     void getAdvances(float* advances) const;
    121 
    122     // Get extents, copying into caller-provided buffer. The size of this buffer must match the
    123     // length of the string (count arg to doLayout).
    124     void getExtents(MinikinExtent* extents) const;
    125 
    126     // The i parameter is an offset within the buf relative to start, it is < count, where
    127     // start and count are the parameters to doLayout
    128     float getCharAdvance(size_t i) const { return mAdvances[i]; }
    129 
    130     void getBounds(MinikinRect* rect) const;
    131     const MinikinRect& getBounds() const { return mBounds; }
    132 
    133     // Purge all caches, useful in low memory conditions
    134     static void purgeCaches();
    135 
    136     // Dump minikin internal statistics, cache usage, cache hit ratio, etc.
    137     static void dumpMinikinStats(int fd);
    138 
    139     uint32_t getMemoryUsage() const {
    140         return sizeof(LayoutGlyph) * nGlyphs() + sizeof(float) * mAdvances.size() +
    141                sizeof(MinikinExtent) * mExtents.size() + sizeof(FakedFont) * mFaces.size() +
    142                sizeof(float /* mAdvance */) + sizeof(MinikinRect /* mBounds */);
    143     }
    144 
    145     // Append another layout (for example, cached value) into this one
    146     void appendLayout(const Layout& src, size_t start, float extraAdvance);
    147 
    148 private:
    149     friend class LayoutCacheKey;
    150     friend class LayoutCache;
    151 
    152     FRIEND_TEST(LayoutTest, doLayoutWithPrecomputedPiecesTest);
    153 
    154     // Find a face in the mFaces vector. If not found, push back the entry to mFaces.
    155     uint8_t findOrPushBackFace(const FakedFont& face);
    156 
    157     // Clears layout, ready to be used again
    158     void reset();
    159 
    160     // Lay out a single bidi run
    161     // When layout is not null, layout info will be stored in the object.
    162     // When advances is not null, measurement results will be stored in the array.
    163     static float doLayoutRunCached(const U16StringPiece& textBuf, const Range& range, bool isRtl,
    164                                    const MinikinPaint& paint, size_t dstStart,
    165                                    StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
    166                                    const LayoutPieces* lpIn, Layout* layout, float* advances,
    167                                    MinikinExtent* extents, MinikinRect* bounds,
    168                                    LayoutPieces* lpOut);
    169 
    170     // Lay out a single word
    171     static float doLayoutWord(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
    172                               bool isRtl, const MinikinPaint& paint, size_t bufStart,
    173                               StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
    174                               const LayoutPieces* lpIn, Layout* layout, float* advances,
    175                               MinikinExtent* extents, MinikinRect* bounds, LayoutPieces* lpOut);
    176 
    177     // Lay out a single bidi run
    178     void doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t bufSize, bool isRtl,
    179                      const MinikinPaint& paint, StartHyphenEdit startHyphen,
    180                      EndHyphenEdit endHyphen);
    181 
    182     std::vector<LayoutGlyph> mGlyphs;
    183 
    184     // The following three vectors are defined per code unit, so their length is identical to the
    185     // input text.
    186     std::vector<float> mAdvances;
    187     std::vector<MinikinExtent> mExtents;
    188 
    189     std::vector<FakedFont> mFaces;
    190     float mAdvance;
    191     MinikinRect mBounds;
    192 };
    193 
    194 }  // namespace minikin
    195 
    196 #endif  // MINIKIN_LAYOUT_H
    197