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 #include "utf8range.h" 31 32 namespace teeui { 33 34 template <typename T> struct HandleDelete; 35 36 template <typename T, typename Deleter = HandleDelete<T>> class Handle { 37 public: Handle()38 Handle() : handle_(nullptr) {} Handle(T handle)39 explicit Handle(T handle) : handle_(handle) {} 40 Handle(const Handle&) = delete; 41 Handle& operator=(const Handle&) = delete; 42 Handle(Handle && other)43 Handle(Handle&& other) { 44 handle_ = other.handle_; 45 other.handle_ = nullptr; 46 } 47 48 Handle& operator=(Handle&& rhs) { 49 if (&rhs != this) { 50 auto dummy = handle_; 51 handle_ = rhs.handle_; 52 rhs.handle_ = dummy; 53 } 54 return *this; 55 } 56 ~Handle()57 ~Handle() { 58 if (handle_) Deleter()(handle_); 59 } 60 61 operator bool() const { return handle_ != nullptr; } 62 T operator*() const { return handle_; } 63 const T operator->() const { return handle_; } 64 T operator->() { return handle_; } 65 66 private: 67 T handle_; 68 }; 69 70 #define MAP_HANDLE_DELETER(type, deleter) \ 71 template <> struct HandleDelete<type> { \ 72 void operator()(type h) { deleter(h); } \ 73 } 74 75 MAP_HANDLE_DELETER(FT_Face, FT_Done_Face); 76 MAP_HANDLE_DELETER(FT_Library, FT_Done_FreeType); 77 78 79 bool isBreakable(unsigned long codePoint); 80 bool isNewline(unsigned long codePoint); 81 82 template <typename CharIterator> class UTF8WordRange { 83 UTF8Range<CharIterator> range_; 84 85 public: UTF8WordRange(CharIterator begin,CharIterator end)86 UTF8WordRange(CharIterator begin, CharIterator end) : range_(begin, end) {} UTF8WordRange(const UTF8Range<CharIterator> & range)87 explicit UTF8WordRange(const UTF8Range<CharIterator>& range) : range_(range) {} 88 UTF8WordRange() = default; 89 UTF8WordRange(const UTF8WordRange&) = default; 90 UTF8WordRange(UTF8WordRange&&) = default; 91 UTF8WordRange& operator=(UTF8WordRange&&) = default; 92 UTF8WordRange& operator=(const UTF8WordRange&) = default; 93 94 using UTF8Iterator = typename UTF8Range<CharIterator>::Iter; 95 class Iter { 96 UTF8Iterator begin_; 97 UTF8Iterator end_; 98 99 public: Iter()100 Iter() : begin_{} {} Iter(UTF8Iterator begin,UTF8Iterator end)101 Iter(UTF8Iterator begin, UTF8Iterator end) : begin_(begin), end_(end) {} Iter(const Iter & rhs)102 Iter(const Iter& rhs) : begin_(rhs.begin_), end_(rhs.end_) {} 103 Iter& operator=(const Iter& rhs) { 104 begin_ = rhs.begin_; 105 end_ = rhs.end_; 106 return *this; 107 } 108 UTF8Iterator operator*() const { return begin_; } 109 Iter& operator++() { 110 if (begin_ == end_) return *this; 111 bool prevBreaking = isBreakable(begin_.codePoint()); 112 // checkAndUpdate detects edges between breakable and non breakable characters. 113 // As a result the iterator stops on the first character of a word or whitespace 114 // sequence. 115 auto checkAndUpdate = [&](unsigned long cp) { 116 bool current = isBreakable(cp); 117 bool result = prevBreaking == current; 118 prevBreaking = current; 119 return result; 120 }; 121 do { 122 ++begin_; 123 } while (begin_ != end_ && checkAndUpdate(begin_.codePoint())); 124 return *this; 125 } 126 Iter operator++(int) { 127 Iter dummy = *this; 128 ++(*this); 129 return dummy; 130 } 131 bool operator==(const Iter& rhs) const { return begin_ == rhs.begin_; } 132 bool operator!=(const Iter& rhs) const { return !(*this == rhs); } 133 }; begin()134 Iter begin() const { return Iter(range_.begin(), range_.end()); } end()135 Iter end() const { return Iter(range_.end(), range_.end()); } 136 }; 137 138 class TextContext; 139 140 using GlyphIndex = unsigned int; 141 142 class TextFace { 143 friend TextContext; 144 Handle<FT_Face> face_; 145 bool hasKerning_ = false; 146 147 public: 148 Error setCharSize(signed long char_size, unsigned int dpi); 149 Error setCharSizeInPix(pxs size); 150 GlyphIndex getCharIndex(unsigned long codePoint); 151 Error loadGlyph(GlyphIndex index); 152 Error renderGlyph(); 153 drawGlyph(const Vec2d<pxs> & pos,const PixelDrawer & drawPixel)154 Error drawGlyph(const Vec2d<pxs>& pos, const PixelDrawer& drawPixel) { 155 FT_Bitmap* bitmap = &face_->glyph->bitmap; 156 uint8_t* rowBuffer = bitmap->buffer; 157 Vec2d<pxs> offset{face_->glyph->bitmap_left, -face_->glyph->bitmap_top}; 158 auto bPos = pos + offset; 159 for (unsigned y = 0; y < bitmap->rows; ++y) { 160 for (unsigned x = 0; x < bitmap->width; ++x) { 161 Color alpha = 0; 162 switch (bitmap->pixel_mode) { 163 case FT_PIXEL_MODE_GRAY: 164 alpha = rowBuffer[x]; 165 alpha *= 256; 166 alpha /= bitmap->num_grays; 167 alpha <<= 24; 168 break; 169 case FT_PIXEL_MODE_LCD: 170 case FT_PIXEL_MODE_BGRA: 171 case FT_PIXEL_MODE_NONE: 172 case FT_PIXEL_MODE_LCD_V: 173 case FT_PIXEL_MODE_MONO: 174 case FT_PIXEL_MODE_GRAY2: 175 case FT_PIXEL_MODE_GRAY4: 176 default: 177 return Error::UnsupportedPixelFormat; 178 } 179 if (drawPixel(bPos.x().count() + x, bPos.y().count() + y, alpha)) { 180 return Error::OutOfBoundsDrawing; 181 } 182 } 183 rowBuffer += bitmap->pitch; 184 } 185 return Error::OK; 186 } 187 188 Vec2d<pxs> advance() const; 189 Vec2d<pxs> kern(GlyphIndex previous) const; 190 optional<Box<pxs>> getGlyphBBox() const; 191 }; 192 193 class TextContext { 194 Handle<FT_Library> library_; 195 196 public: 197 static std::tuple<Error, TextContext> create(); 198 199 template <typename Buffer> 200 std::tuple<Error, TextFace> loadFace(const Buffer& data, signed long face_index = 0) { 201 std::tuple<Error, TextFace> result; 202 auto& [rc, tface] = result; 203 rc = Error::NotInitialized; 204 if (!library_) return result; 205 FT_Face face; 206 auto error = FT_New_Memory_Face(*library_, data.data(), data.size(), face_index, &face); 207 rc = Error::FaceNotLoaded; 208 if (error) return result; 209 tface.face_ = Handle(face); 210 tface.hasKerning_ = FT_HAS_KERNING(face); 211 rc = Error::OK; 212 return result; 213 } 214 }; 215 216 std::tuple<Error, Box<pxs>, UTF8Range<const char*>> 217 findLongestWordSequence(TextFace* face, const UTF8Range<const char*>& text, 218 const Box<pxs>& boundingBox); 219 Error drawText(TextFace* face, const UTF8Range<const char*>& text, const PixelDrawer& drawPixel, 220 PxPoint pen); 221 222 } // namespace teeui 223 224 #endif // TEEUI_LIBTEEUI_FONT_RENDERING_H_ 225