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