1 /* 2 * 3 * Copyright 2019, The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #ifndef TEEUI_LIBTEEUI_FONT_RENDERING_H_ 19 #define TEEUI_LIBTEEUI_FONT_RENDERING_H_ 20 21 #include <ft2build.h> 22 #include FT_FREETYPE_H 23 #include <freetype/ftglyph.h> 24 25 #include "utils.h" 26 #include <tuple> 27 28 #include <type_traits> 29 30 namespace teeui { 31 32 template <typename T> struct HandleDelete; 33 34 template <typename T, typename Deleter = HandleDelete<T>> class Handle { 35 public: Handle()36 Handle() : handle_(nullptr) {} Handle(T handle)37 explicit Handle(T handle) : handle_(handle) {} 38 Handle(const Handle&) = delete; 39 Handle& operator=(const Handle&) = delete; 40 Handle(Handle && other)41 Handle(Handle&& other) { 42 handle_ = other.handle_; 43 other.handle_ = nullptr; 44 } 45 46 Handle& operator=(Handle&& rhs) { 47 if (&rhs != this) { 48 auto dummy = handle_; 49 handle_ = rhs.handle_; 50 rhs.handle_ = dummy; 51 } 52 return *this; 53 } 54 ~Handle()55 ~Handle() { 56 if (handle_) Deleter()(handle_); 57 } 58 59 operator bool() const { return handle_ != nullptr; } 60 T operator*() const { return handle_; } 61 const T operator->() const { return handle_; } 62 T operator->() { return handle_; } 63 64 private: 65 T handle_; 66 }; 67 68 #define MAP_HANDLE_DELETER(type, deleter) \ 69 template <> struct HandleDelete<type> { \ 70 void operator()(type h) { deleter(h); } \ 71 } 72 73 MAP_HANDLE_DELETER(FT_Face, FT_Done_Face); 74 MAP_HANDLE_DELETER(FT_Library, FT_Done_FreeType); 75 76 /** 77 * Important notice. The UTF8Range only works on verified UTF8 encoded strings. 78 * E.g. if the string successfully passed through our CBOR formatting (see cbor.h) it is safe to 79 * use with UTF8Range. Alternatively, you can call verify() on a new range. 80 */ 81 template <typename CharIterator> class UTF8Range { 82 public: UTF8Range(CharIterator begin,CharIterator end)83 UTF8Range(CharIterator begin, CharIterator end) : begin_(begin), end_(end) {} UTF8Range()84 UTF8Range() : begin_{}, end_{begin_} {}; 85 UTF8Range(const UTF8Range&) = default; 86 UTF8Range(UTF8Range&&) = default; 87 UTF8Range& operator=(UTF8Range&&) = default; 88 UTF8Range& operator=(const UTF8Range&) = default; 89 90 /** 91 * Decodes a header byte of a UTF8 sequence. In UTF8 encoding the number of leading ones 92 * indicate the length of the UTF8 sequence. Following bytes start with b10 followed by six 93 * payload bits. Sequences of length one start with a 0 followed by 7 payload bits. 94 */ byteCount(char c)95 static size_t byteCount(char c) { 96 if (0x80 & c) { 97 /* 98 * CLZ - count leading zeroes. 99 * __builtin_clz promotes the argument to unsigned int. 100 * We invert c to turn leading ones into leading zeroes. 101 * We subtract additional leading zeroes due to the type promotion from the result. 102 */ 103 return __builtin_clz((unsigned char)(~c)) - (sizeof(unsigned int) * 8 - 8); 104 } else { 105 return 1; 106 } 107 } codePoint(CharIterator begin)108 static unsigned long codePoint(CharIterator begin) { 109 unsigned long c = (uint8_t)*begin; 110 size_t byte_count = byteCount(c); 111 if (byte_count == 1) { 112 return c; 113 } else { 114 // multi byte 115 unsigned long result = c & ~(0xff << (8 - byte_count)); 116 ++begin; 117 for (size_t i = 1; i < byte_count; ++i) { 118 result <<= 6; 119 result |= *begin & 0x3f; 120 ++begin; 121 } 122 return result; 123 } 124 } 125 126 class Iter { 127 CharIterator begin_; 128 129 public: Iter()130 Iter() : begin_{} {} Iter(CharIterator begin)131 Iter(CharIterator begin) : begin_(begin) {} Iter(const Iter & rhs)132 Iter(const Iter& rhs) : begin_(rhs.begin_) {} 133 Iter& operator=(const Iter& rhs) { 134 begin_ = rhs.begin_; 135 return *this; 136 } 137 CharIterator operator*() const { return begin_; } 138 Iter& operator++() { 139 begin_ += byteCount(*begin_); 140 return *this; 141 } 142 Iter operator++(int) { 143 Iter dummy = *this; 144 ++(*this); 145 return dummy; 146 } 147 bool operator==(const Iter& rhs) const { return begin_ == rhs.begin_; } 148 bool operator!=(const Iter& rhs) const { return !(*this == rhs); } codePoint()149 unsigned long codePoint() const { return UTF8Range::codePoint(begin_); } 150 }; begin()151 Iter begin() const { return Iter(begin_); } end()152 Iter end() const { return Iter(end_); } 153 /* 154 * Checks if the range is safe to use. If this returns false, iteration over this range is 155 * undefined. It may infinite loop and read out of bounds. 156 */ verify()157 bool verify() { 158 for (auto pos = begin_; pos != end_;) { 159 // are we out of sync? 160 if ((*pos & 0xc0) == 0x80) return false; 161 auto byte_count = byteCount(*pos); 162 // did we run out of buffer; 163 if (end_ - pos < byte_count) return false; 164 // we could check if the non header bytes have the wrong header. While this would 165 // be malformed UTF8, it does not impact control flow and is thus not security 166 // critical. 167 pos += byte_count; 168 } 169 return true; 170 } 171 172 private: 173 CharIterator begin_; 174 CharIterator end_; 175 static_assert(std::is_same<std::remove_reference_t<decltype(*begin_)>, const char>::value, 176 "Iterator must dereference to const char"); 177 static_assert( 178 std::is_convertible<std::remove_reference_t<decltype(end_ - begin_)>, size_t>::value, 179 "Iterator arithmetic must evaluate to something that is convertible to size_t"); 180 }; 181 182 bool isBreakable(unsigned long codePoint); 183 184 template <typename CharIterator> class UTF8WordRange { 185 UTF8Range<CharIterator> range_; 186 187 public: UTF8WordRange(CharIterator begin,CharIterator end)188 UTF8WordRange(CharIterator begin, CharIterator end) : range_(begin, end) {} UTF8WordRange(const UTF8Range<CharIterator> & range)189 explicit UTF8WordRange(const UTF8Range<CharIterator>& range) : range_(range) {} 190 UTF8WordRange() = default; 191 UTF8WordRange(const UTF8WordRange&) = default; 192 UTF8WordRange(UTF8WordRange&&) = default; 193 UTF8WordRange& operator=(UTF8WordRange&&) = default; 194 UTF8WordRange& operator=(const UTF8WordRange&) = default; 195 196 using UTF8Iterator = typename UTF8Range<CharIterator>::Iter; 197 class Iter { 198 UTF8Iterator begin_; 199 UTF8Iterator end_; 200 201 public: Iter()202 Iter() : begin_{} {} Iter(UTF8Iterator begin,UTF8Iterator end)203 Iter(UTF8Iterator begin, UTF8Iterator end) : begin_(begin), end_(end) {} Iter(const Iter & rhs)204 Iter(const Iter& rhs) : begin_(rhs.begin_), end_(rhs.end_) {} 205 Iter& operator=(const Iter& rhs) { 206 begin_ = rhs.begin_; 207 end_ = rhs.end_; 208 return *this; 209 } 210 UTF8Iterator operator*() const { return begin_; } 211 Iter& operator++() { 212 if (begin_ == end_) return *this; 213 bool prevBreaking = isBreakable(begin_.codePoint()); 214 // checkAndUpdate detects edges between breakable and non breakable characters. 215 // As a result the iterator stops on the first character of a word or whitespace 216 // sequence. 217 auto checkAndUpdate = [&](unsigned long cp) { 218 bool current = isBreakable(cp); 219 bool result = prevBreaking == current; 220 prevBreaking = current; 221 return result; 222 }; 223 do { 224 ++begin_; 225 } while (begin_ != end_ && checkAndUpdate(begin_.codePoint())); 226 return *this; 227 } 228 Iter operator++(int) { 229 Iter dummy = *this; 230 ++(*this); 231 return dummy; 232 } 233 bool operator==(const Iter& rhs) const { return begin_ == rhs.begin_; } 234 bool operator!=(const Iter& rhs) const { return !(*this == rhs); } 235 }; begin()236 Iter begin() const { return Iter(range_.begin(), range_.end()); } end()237 Iter end() const { return Iter(range_.end(), range_.end()); } 238 }; 239 240 class TextContext; 241 242 using GlyphIndex = unsigned int; 243 244 class TextFace { 245 friend TextContext; 246 Handle<FT_Face> face_; 247 bool hasKerning_ = false; 248 249 public: 250 Error setCharSize(signed long char_size, unsigned int dpi); 251 Error setCharSizeInPix(pxs size); 252 GlyphIndex getCharIndex(unsigned long codePoint); 253 Error loadGlyph(GlyphIndex index); 254 Error renderGlyph(); 255 drawGlyph(const Vec2d<pxs> & pos,const PixelDrawer & drawPixel)256 Error drawGlyph(const Vec2d<pxs>& pos, const PixelDrawer& drawPixel) { 257 FT_Bitmap* bitmap = &face_->glyph->bitmap; 258 uint8_t* rowBuffer = bitmap->buffer; 259 Vec2d<pxs> offset{face_->glyph->bitmap_left, -face_->glyph->bitmap_top}; 260 auto bPos = pos + offset; 261 for (unsigned y = 0; y < bitmap->rows; ++y) { 262 for (unsigned x = 0; x < bitmap->width; ++x) { 263 Color alpha = 0; 264 switch (bitmap->pixel_mode) { 265 case FT_PIXEL_MODE_GRAY: 266 alpha = rowBuffer[x]; 267 alpha *= 256; 268 alpha /= bitmap->num_grays; 269 alpha <<= 24; 270 break; 271 case FT_PIXEL_MODE_LCD: 272 case FT_PIXEL_MODE_BGRA: 273 case FT_PIXEL_MODE_NONE: 274 case FT_PIXEL_MODE_LCD_V: 275 case FT_PIXEL_MODE_MONO: 276 case FT_PIXEL_MODE_GRAY2: 277 case FT_PIXEL_MODE_GRAY4: 278 default: 279 return Error::UnsupportedPixelFormat; 280 } 281 if (drawPixel(bPos.x().count() + x, bPos.y().count() + y, alpha)) { 282 return Error::OutOfBoundsDrawing; 283 } 284 } 285 rowBuffer += bitmap->pitch; 286 } 287 return Error::OK; 288 } 289 290 Vec2d<pxs> advance() const; 291 Vec2d<pxs> kern(GlyphIndex previous) const; 292 optional<Box<pxs>> getGlyphBBox() const; 293 }; 294 295 class TextContext { 296 Handle<FT_Library> library_; 297 298 public: 299 static std::tuple<Error, TextContext> create(); 300 301 template <typename Buffer> 302 std::tuple<Error, TextFace> loadFace(const Buffer& data, signed long face_index = 0) { 303 std::tuple<Error, TextFace> result; 304 auto& [rc, tface] = result; 305 rc = Error::NotInitialized; 306 if (!library_) return result; 307 FT_Face face; 308 auto error = FT_New_Memory_Face(*library_, data.data(), data.size(), face_index, &face); 309 rc = Error::FaceNotLoaded; 310 if (error) return result; 311 tface.face_ = Handle(face); 312 tface.hasKerning_ = FT_HAS_KERNING(face); 313 rc = Error::OK; 314 return result; 315 } 316 }; 317 318 std::tuple<Error, Box<pxs>, UTF8Range<const char*>> 319 findLongestWordSequence(TextFace* face, const UTF8Range<const char*>& text, 320 const Box<pxs>& boundingBox); 321 Error drawText(TextFace* face, const UTF8Range<const char*>& text, const PixelDrawer& drawPixel, 322 PxPoint pen); 323 324 } // namespace teeui 325 326 #endif // TEEUI_LIBTEEUI_FONT_RENDERING_H_ 327