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), 34 hyphenEdit(hyphenEdit), 35 dir(dir), 36 paintId(paintId), 37 hash(calcHash()) {} 38 39 Range range; 40 HyphenEdit hyphenEdit; 41 bool dir; 42 uint32_t paintId; 43 uint32_t hash; 44 calcHashLayoutPieces::Key45 uint32_t calcHash() const { 46 return Hasher() 47 .update(range.getStart()) 48 .update(range.getEnd()) 49 .update(hyphenEdit) 50 .update(dir) 51 .update(paintId) 52 .hash(); 53 } 54 55 bool operator==(const Key& o) const { 56 return range == o.range && hyphenEdit == o.hyphenEdit && dir == o.dir && 57 paintId == o.paintId; 58 } 59 getMemoryUsageLayoutPieces::Key60 uint32_t getMemoryUsage() const { 61 return sizeof(Range) + sizeof(HyphenEdit) + sizeof(bool) + sizeof(uint32_t); 62 } 63 }; 64 65 struct KeyHasher { operatorLayoutPieces::KeyHasher66 std::size_t operator()(const Key& key) const { return key.hash; } 67 }; 68 69 struct PaintHasher { operatorLayoutPieces::PaintHasher70 std::size_t operator()(const MinikinPaint& paint) const { return paint.hash(); } 71 }; 72 LayoutPiecesLayoutPieces73 LayoutPieces() : nextPaintId(0) {} ~LayoutPiecesLayoutPieces74 ~LayoutPieces() {} 75 76 uint32_t nextPaintId; 77 std::unordered_map<MinikinPaint, uint32_t, PaintHasher> paintMap; 78 std::unordered_map<Key, LayoutSlot, KeyHasher> offsetMap; 79 insertLayoutPieces80 void insert(const Range& range, HyphenEdit edit, const LayoutPiece& layout, bool dir, 81 const MinikinPaint& paint, const MinikinRect& rect) { 82 uint32_t paintId = findPaintId(paint); 83 if (paintId == kNoPaintId) { 84 paintId = nextPaintId++; 85 paintMap.insert(std::make_pair(paint, paintId)); 86 } 87 offsetMap.emplace(std::piecewise_construct, 88 std::forward_as_tuple(range, edit, dir, paintId), 89 std::forward_as_tuple(layout, rect)); 90 } 91 92 template <typename F> getOrCreateLayoutPieces93 void getOrCreate(const U16StringPiece& textBuf, const Range& range, const Range& context, 94 const MinikinPaint& paint, bool dir, StartHyphenEdit startEdit, 95 EndHyphenEdit endEdit, uint32_t paintId, bool boundsCalculation, F& f) const { 96 const HyphenEdit edit = packHyphenEdit(startEdit, endEdit); 97 auto it = offsetMap.find(Key(range, edit, dir, paintId)); 98 if (it != offsetMap.end()) { 99 const LayoutPiece& piece = it->second.mLayout; 100 const MinikinRect& bounds = it->second.mBounds; 101 if (boundsCalculation && !bounds.isValid()) { 102 f(piece, paint, LayoutPiece::calculateBounds(piece, paint)); 103 } else { 104 f(piece, paint, bounds); 105 } 106 return; 107 } 108 109 LayoutCache::getInstance().getOrCreate(textBuf.substr(context), range - context.getStart(), 110 paint, dir, startEdit, endEdit, boundsCalculation, 111 f); 112 } 113 findPaintIdLayoutPieces114 uint32_t findPaintId(const MinikinPaint& paint) const { 115 auto paintIt = paintMap.find(paint); 116 return paintIt == paintMap.end() ? kNoPaintId : paintIt->second; 117 } 118 getMemoryUsageLayoutPieces119 uint32_t getMemoryUsage() const { 120 uint32_t result = 0; 121 for (const auto& i : offsetMap) { 122 result += i.first.getMemoryUsage() + i.second.mLayout.getMemoryUsage(); 123 } 124 result += (sizeof(MinikinPaint) + sizeof(uint32_t)) * paintMap.size(); 125 return result; 126 } 127 }; 128 129 } // namespace minikin 130 131 #endif // MINIKIN_LAYOUT_PIECES_H 132