• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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