1 /*
2  * Copyright (C) 2018 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_PIECES_H
18 #define MINIKIN_LAYOUT_PIECES_H
19 
20 #include <unordered_map>
21 
22 #include "minikin/LayoutCache.h"
23 #include "minikin/LayoutCore.h"
24 #include "minikin/MinikinPaint.h"
25 
26 namespace minikin {
27 
28 struct LayoutPieces {
29     const static uint32_t kNoPaintId = static_cast<uint32_t>(-1);
30 
31     struct Key {
KeyLayoutPieces::Key32         Key(const Range& range, HyphenEdit hyphenEdit, bool dir, uint32_t paintId)
33                 : range(range), hyphenEdit(hyphenEdit), dir(dir), paintId(paintId) {}
34 
35         Range range;
36         HyphenEdit hyphenEdit;
37         bool dir;
38         uint32_t paintId;
39 
hashLayoutPieces::Key40         uint32_t hash() const {
41             return Hasher()
42                     .update(range.getStart())
43                     .update(range.getEnd())
44                     .update(hyphenEdit)
45                     .update(dir)
46                     .update(paintId)
47                     .hash();
48         }
49 
50         bool operator==(const Key& o) const {
51             return range == o.range && hyphenEdit == o.hyphenEdit && dir == o.dir &&
52                    paintId == o.paintId;
53         }
54 
getMemoryUsageLayoutPieces::Key55         uint32_t getMemoryUsage() const {
56             return sizeof(Range) + sizeof(HyphenEdit) + sizeof(bool) + sizeof(uint32_t);
57         }
58     };
59 
60     struct KeyHasher {
operatorLayoutPieces::KeyHasher61         std::size_t operator()(const Key& key) const { return key.hash(); }
62     };
63 
64     struct PaintHasher {
operatorLayoutPieces::PaintHasher65         std::size_t operator()(const MinikinPaint& paint) const { return paint.hash(); }
66     };
67 
LayoutPiecesLayoutPieces68     LayoutPieces() : nextPaintId(0) {}
~LayoutPiecesLayoutPieces69     ~LayoutPieces() {}
70 
71     uint32_t nextPaintId;
72     std::unordered_map<MinikinPaint, uint32_t, PaintHasher> paintMap;
73     std::unordered_map<Key, LayoutPiece, KeyHasher> offsetMap;
74 
insertLayoutPieces75     void insert(const Range& range, HyphenEdit edit, const LayoutPiece& layout, bool dir,
76                 const MinikinPaint& paint) {
77         uint32_t paintId = findPaintId(paint);
78         if (paintId == kNoPaintId) {
79             paintId = nextPaintId++;
80             paintMap.insert(std::make_pair(paint, paintId));
81         }
82         offsetMap.emplace(std::piecewise_construct,
83                           std::forward_as_tuple(range, edit, dir, paintId),
84                           std::forward_as_tuple(layout));
85     }
86 
87     template <typename F>
getOrCreateLayoutPieces88     void getOrCreate(const U16StringPiece& textBuf, const Range& range, const Range& context,
89                      const MinikinPaint& paint, bool dir, StartHyphenEdit startEdit,
90                      EndHyphenEdit endEdit, uint32_t paintId, F& f) const {
91         const HyphenEdit edit = packHyphenEdit(startEdit, endEdit);
92         auto it = offsetMap.find(Key(range, edit, dir, paintId));
93         if (it == offsetMap.end()) {
94             LayoutCache::getInstance().getOrCreate(textBuf.substr(context),
95                                                    range - context.getStart(), paint, dir,
96                                                    startEdit, endEdit, f);
97         } else {
98             f(it->second, paint);
99         }
100     }
101 
findPaintIdLayoutPieces102     uint32_t findPaintId(const MinikinPaint& paint) const {
103         auto paintIt = paintMap.find(paint);
104         return paintIt == paintMap.end() ? kNoPaintId : paintIt->second;
105     }
106 
getMemoryUsageLayoutPieces107     uint32_t getMemoryUsage() const {
108         uint32_t result = 0;
109         for (const auto& i : offsetMap) {
110             result += i.first.getMemoryUsage() + i.second.getMemoryUsage();
111         }
112         result += (sizeof(MinikinPaint) + sizeof(uint32_t)) * paintMap.size();
113         return result;
114     }
115 };
116 
117 }  // namespace minikin
118 
119 #endif  // MINIKIN_LAYOUT_PIECES_H
120