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