xref: /aosp_15_r20/system/teeui/libteeui/include/teeui/font_rendering.h (revision 20bfefbe1966c142a35ae1ab84a8af250b3fd403)
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