Charlie Jiang pushed to branch gsoc-2022-chariri-2 at FreeType / FreeType Demo Programs
Commits:
-
cd132d4b
by Charlie Jiang at 2022-07-15T18:39:38+08:00
7 changed files:
- src/ftinspect/engine/engine.cpp
- src/ftinspect/engine/engine.hpp
- src/ftinspect/rendering/glyphbitmap.cpp
- src/ftinspect/rendering/glyphcontinuous.cpp
- src/ftinspect/rendering/glyphcontinuous.hpp
- src/ftinspect/rendering/renderutils.cpp
- src/ftinspect/rendering/renderutils.hpp
Changes:
... | ... | @@ -453,7 +453,7 @@ Engine::loadGlyphWithoutUpdate(int glyphIndex) |
453 | 453 | |
454 | 454 | |
455 | 455 | bool
|
456 | -Engine::glyphToBitmap(FT_Glyph src,
|
|
456 | +Engine::convertGlyphToBitmapGlyph(FT_Glyph src,
|
|
457 | 457 | FT_Glyph* out)
|
458 | 458 | {
|
459 | 459 | if (src->format == FT_GLYPH_FORMAT_BITMAP)
|
... | ... | @@ -739,16 +739,11 @@ convertLCDVToARGB(FT_Bitmap& bitmap, |
739 | 739 | |
740 | 740 | |
741 | 741 | QImage*
|
742 | -Engine::convertBitmapToQImage(FT_Glyph src,
|
|
743 | - QRect* outRect)
|
|
742 | +Engine::convertBitmapToQImage(FT_Bitmap* src)
|
|
744 | 743 | {
|
745 | 744 | QImage* result = NULL;
|
746 | - FT_BitmapGlyph bitmapGlyph;
|
|
747 | - bool ownBitmapGlyph
|
|
748 | - = glyphToBitmap(src, reinterpret_cast<FT_Glyph*>(&bitmapGlyph));
|
|
749 | - if (!bitmapGlyph)
|
|
750 | - return result;
|
|
751 | - auto& bmap = bitmapGlyph->bitmap;
|
|
745 | +
|
|
746 | + auto& bmap = *src;
|
|
752 | 747 | bool ownBitmap = false;
|
753 | 748 | |
754 | 749 | int width = bmap.width;
|
... | ... | @@ -769,14 +764,6 @@ Engine::convertBitmapToQImage(FT_Glyph src, |
769 | 764 | else if (bmap.pixel_mode == FT_PIXEL_MODE_LCD_V)
|
770 | 765 | height /= 3;
|
771 | 766 | |
772 | - if (outRect)
|
|
773 | - {
|
|
774 | - outRect->setLeft(bitmapGlyph->left);
|
|
775 | - outRect->setTop(-bitmapGlyph->top);
|
|
776 | - outRect->setWidth(width);
|
|
777 | - outRect->setHeight(height);
|
|
778 | - }
|
|
779 | - |
|
780 | 767 | switch (bmap.pixel_mode)
|
781 | 768 | {
|
782 | 769 | case FT_PIXEL_MODE_MONO:
|
... | ... | @@ -827,8 +814,6 @@ Engine::convertBitmapToQImage(FT_Glyph src, |
827 | 814 | }
|
828 | 815 | |
829 | 816 | cleanup:
|
830 | - if (ownBitmapGlyph)
|
|
831 | - FT_Done_Glyph(reinterpret_cast<FT_Glyph>(bitmapGlyph));
|
|
832 | 817 | if (ownBitmap)
|
833 | 818 | FT_Bitmap_Done(library_, &bmap);
|
834 | 819 | |
... | ... | @@ -836,6 +821,57 @@ cleanup: |
836 | 821 | }
|
837 | 822 | |
838 | 823 | |
824 | +QImage*
|
|
825 | +Engine::convertGlyphToQImage(FT_Glyph src, QRect* outRect)
|
|
826 | +{
|
|
827 | + FT_BitmapGlyph bitmapGlyph;
|
|
828 | + bool ownBitmapGlyph
|
|
829 | + = convertGlyphToBitmapGlyph(src, reinterpret_cast<FT_Glyph*>(&bitmapGlyph));
|
|
830 | + if (!bitmapGlyph)
|
|
831 | + return NULL;
|
|
832 | + |
|
833 | + auto result = convertBitmapToQImage(&bitmapGlyph->bitmap);
|
|
834 | + |
|
835 | + if (result && outRect)
|
|
836 | + {
|
|
837 | + outRect->setLeft(bitmapGlyph->left);
|
|
838 | + outRect->setTop(-bitmapGlyph->top);
|
|
839 | + outRect->setWidth(bitmapGlyph->bitmap.width);
|
|
840 | + outRect->setHeight(bitmapGlyph->bitmap.rows);
|
|
841 | + }
|
|
842 | + |
|
843 | + if (ownBitmapGlyph)
|
|
844 | + FT_Done_Glyph(reinterpret_cast<FT_Glyph>(bitmapGlyph));
|
|
845 | + |
|
846 | + return result;
|
|
847 | +}
|
|
848 | + |
|
849 | + |
|
850 | +QPoint
|
|
851 | +Engine::computeGlyphOffset(FT_Glyph glyph)
|
|
852 | +{
|
|
853 | + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE)
|
|
854 | + {
|
|
855 | + FT_BBox cbox;
|
|
856 | + FT_Outline_Get_CBox(&reinterpret_cast<FT_OutlineGlyph>(glyph)->outline,
|
|
857 | + &cbox);
|
|
858 | + cbox.xMin &= ~63;
|
|
859 | + cbox.yMin &= ~63;
|
|
860 | + cbox.xMax = (cbox.xMax + 63) & ~63;
|
|
861 | + cbox.yMax = (cbox.yMax + 63) & ~63;
|
|
862 | + return { static_cast<int>(cbox.xMin) / 64,
|
|
863 | + static_cast<int>(-cbox.yMax / 64) };
|
|
864 | + }
|
|
865 | + if (glyph->format == FT_GLYPH_FORMAT_BITMAP)
|
|
866 | + {
|
|
867 | + auto bg = reinterpret_cast<FT_BitmapGlyph>(glyph);
|
|
868 | + return { bg->left, -bg->top };
|
|
869 | + }
|
|
870 | + |
|
871 | + return {};
|
|
872 | +}
|
|
873 | + |
|
874 | + |
|
839 | 875 | QHash<FT_Glyph_Format, QString> glyphFormatNamesCache;
|
840 | 876 | QHash<FT_Glyph_Format, QString>&
|
841 | 877 | glyphFormatNames()
|
... | ... | @@ -105,9 +105,11 @@ public: |
105 | 105 | |
106 | 106 | // Return `true` if you need to free `out`
|
107 | 107 | // `out` will be set to NULL in cases of error
|
108 | - bool glyphToBitmap(FT_Glyph src, FT_Glyph* out);
|
|
108 | + bool convertGlyphToBitmapGlyph(FT_Glyph src, FT_Glyph* out);
|
|
109 | 109 | FT_Bitmap convertBitmapTo8Bpp(FT_Bitmap* bitmap);
|
110 | - QImage* convertBitmapToQImage(FT_Glyph src, QRect* outRect);
|
|
110 | + QImage* convertBitmapToQImage(FT_Bitmap* src);
|
|
111 | + QImage* convertGlyphToQImage(FT_Glyph src, QRect* outRect);
|
|
112 | + QPoint computeGlyphOffset(FT_Glyph glyph);
|
|
111 | 113 | |
112 | 114 | // reload current triplet, but with updated settings, useful for updating
|
113 | 115 | // `ftSize_` only
|
... | ... | @@ -18,7 +18,7 @@ GlyphBitmap::GlyphBitmap(FT_Glyph glyph, |
18 | 18 | Engine* engine)
|
19 | 19 | {
|
20 | 20 | QRect bRect;
|
21 | - image_ = engine->convertBitmapToQImage(glyph, &bRect);
|
|
21 | + image_ = engine->convertGlyphToQImage(glyph, &bRect);
|
|
22 | 22 | boundingRect_ = bRect; // QRectF to QRect
|
23 | 23 | }
|
24 | 24 |
... | ... | @@ -11,13 +11,14 @@ |
11 | 11 | #include <QPainter>
|
12 | 12 | #include <QWheelEvent>
|
13 | 13 | |
14 | +#include <freetype/ftbitmap.h>
|
|
15 | + |
|
14 | 16 | |
15 | 17 | GlyphContinuous::GlyphContinuous(QWidget* parent, Engine* engine)
|
16 | 18 | : QWidget(parent), engine_(engine)
|
17 | 19 | {
|
18 | 20 | setAcceptDrops(false);
|
19 | 21 | setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
20 | - graphicsDefault_ = GraphicsDefault::deafultInstance();
|
|
21 | 22 | |
22 | 23 | FT_Stroker_New(engine_->ftLibrary(), &stroker_);
|
23 | 24 | }
|
... | ... | @@ -99,10 +100,10 @@ GlyphContinuous::paintAG(QPainter* painter) |
99 | 100 | switch (mode_)
|
100 | 101 | {
|
101 | 102 | case M_Fancy:
|
102 | - transformGlyphAGFancy();
|
|
103 | + transformGlyphFancy();
|
|
103 | 104 | break;
|
104 | 105 | case M_Stroked:
|
105 | - transformGlyphAGStroked();
|
|
106 | + transformGlyphStroked();
|
|
106 | 107 | break;
|
107 | 108 | default:;
|
108 | 109 | }
|
... | ... | @@ -118,7 +119,7 @@ GlyphContinuous::paintAG(QPainter* painter) |
118 | 119 | |
119 | 120 | |
120 | 121 | void
|
121 | -GlyphContinuous::transformGlyphAGFancy()
|
|
122 | +GlyphContinuous::transformGlyphFancy()
|
|
122 | 123 | {
|
123 | 124 | // adopted from ftview.c:289
|
124 | 125 | /***************************************************************/
|
... | ... | @@ -146,41 +147,52 @@ GlyphContinuous::transformGlyphAGFancy() |
146 | 147 | xstr = (FT_Pos)(metrics_.y_ppem * 64 * boldX_);
|
147 | 148 | ystr = (FT_Pos)(metrics_.y_ppem * 64 * boldY_);
|
148 | 149 | |
149 | - if (!isGlyphCloned_)
|
|
150 | - cloneGlyph();
|
|
151 | - |
|
152 | - if (glyph_->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
153 | - return; // TODO suuport non-outline: code below all depend on `outline_`!
|
|
154 | - |
|
155 | - FT_Outline_Transform(&outline_, &shear);
|
|
156 | - FT_Outline_EmboldenXY(&outline_, xstr, ystr);
|
|
150 | + if (glyph_->format == FT_GLYPH_FORMAT_OUTLINE)
|
|
151 | + {
|
|
152 | + if (!isGlyphCloned_)
|
|
153 | + cloneGlyph();
|
|
154 | + FT_Outline_Transform(&outline_, &shear);
|
|
155 | + if (FT_Outline_EmboldenXY(&outline_, xstr, ystr))
|
|
156 | + {
|
|
157 | + // XXX error handling?
|
|
158 | + return;
|
|
159 | + }
|
|
157 | 160 | |
158 | - if (glyph_->advance.x)
|
|
159 | - glyph_->advance.x += xstr;
|
|
161 | + if (glyph_->advance.x)
|
|
162 | + glyph_->advance.x += xstr;
|
|
160 | 163 | |
161 | - if (glyph_->advance.y)
|
|
162 | - glyph_->advance.y += ystr;
|
|
163 | -
|
|
164 | - //glyph_->metrics.width += xstr;
|
|
165 | - //glyph_->metrics.height += ystr;
|
|
166 | - //glyph_->metrics.horiAdvance += xstr;
|
|
167 | - //glyph_->metrics.vertAdvance += ystr;
|
|
164 | + if (glyph_->advance.y)
|
|
165 | + glyph_->advance.y += ystr;
|
|
166 | + }
|
|
167 | + else if (glyph_->format == FT_GLYPH_FORMAT_BITMAP)
|
|
168 | + {
|
|
169 | + if (!isBitmapCloned_)
|
|
170 | + cloneBitmap();
|
|
171 | + xstr &= ~63;
|
|
172 | + ystr &= ~63;
|
|
173 | + |
|
174 | + // No shearing support for bitmap
|
|
175 | + FT_Bitmap_Embolden(engine_->ftLibrary(), &bitmap_,
|
|
176 | + xstr, ystr);
|
|
177 | + }
|
|
178 | + else
|
|
179 | + return; // XXX no support for SVG
|
|
168 | 180 | }
|
169 | 181 | |
170 | 182 | |
171 | 183 | void
|
172 | -GlyphContinuous::transformGlyphAGStroked()
|
|
184 | +GlyphContinuous::transformGlyphStroked()
|
|
173 | 185 | {
|
174 | - //if (!isGlyphCloned_)
|
|
175 | - //cloneGlyph();
|
|
176 | - // Well, now here only outline glyph is supported.
|
|
186 | + // Well, here only outline glyph is supported.
|
|
177 | 187 | if (glyph_->format != FT_GLYPH_FORMAT_OUTLINE)
|
178 | 188 | return;
|
189 | + auto oldGlyph = glyph_;
|
|
179 | 190 | auto error = FT_Glyph_Stroke(&glyph_, stroker_, 0);
|
180 | 191 | if (!error)
|
181 | 192 | {
|
193 | + if (isGlyphCloned_)
|
|
194 | + FT_Done_Glyph(oldGlyph);
|
|
182 | 195 | isGlyphCloned_ = true;
|
183 | - isOutlineCloned_ = false;
|
|
184 | 196 | outline_ = reinterpret_cast<FT_OutlineGlyph>(glyph_)->outline;
|
185 | 197 | }
|
186 | 198 | }
|
... | ... | @@ -228,61 +240,19 @@ GlyphContinuous::paintChar(QPainter* painter) |
228 | 240 | // XXX: this is different from what's being done in
|
229 | 241 | // `ftcommon.c`:FTDemo_Draw_Slot: is this correct??
|
230 | 242 | |
231 | - // First translate the outline
|
|
232 | - |
|
233 | - if (glyph_->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
234 | - return true; // XXX only outline is supported - need to impl others later
|
|
235 | - |
|
236 | - FT_BBox cbox;
|
|
237 | - // Don't forget to free this when returning
|
|
238 | - if (!isOutlineCloned_ && !isGlyphCloned_)
|
|
239 | - cloneOutline();
|
|
243 | + QImage* image;
|
|
240 | 244 |
|
241 | - transformOutlineToOrigin(&outline_, &cbox);
|
|
242 | -
|
|
243 | - auto outlineWidth = (cbox.xMax - cbox.xMin) / 64;
|
|
244 | - auto outlineHeight = (cbox.yMax - cbox.yMin) / 64;
|
|
245 | - |
|
246 | - // Then convert to bitmap
|
|
247 | - FT_Bitmap bitmap;
|
|
248 | - QImage::Format format = QImage::Format_Indexed8;
|
|
249 | - auto aaEnabled = engine_->antiAliasingEnabled();
|
|
250 | - |
|
251 | - // TODO cover LCD and color
|
|
252 | - if (!aaEnabled)
|
|
253 | - format = QImage::Format_Mono;
|
|
254 | - |
|
255 | - // TODO optimization: reuse QImage?
|
|
256 | - QImage image(QSize(outlineWidth, outlineHeight), format);
|
|
257 | - |
|
258 | - if (!aaEnabled)
|
|
259 | - image.setColorTable(graphicsDefault_->monoColorTable);
|
|
245 | + if (bitmap_.buffer) // Always prefer `bitmap_` since it can be manipulated
|
|
246 | + image = engine_->convertBitmapToQImage(&bitmap_);
|
|
260 | 247 | else
|
261 | - image.setColorTable(graphicsDefault_->grayColorTable);
|
|
248 | + image = engine_->convertGlyphToQImage(glyph_, NULL);
|
|
249 | + auto offset = engine_->computeGlyphOffset(glyph_);
|
|
262 | 250 | |
263 | - image.fill(0);
|
|
264 | - |
|
265 | - bitmap.rows = static_cast<unsigned int>(outlineHeight);
|
|
266 | - bitmap.width = static_cast<unsigned int>(outlineWidth);
|
|
267 | - bitmap.buffer = image.bits();
|
|
268 | - bitmap.pitch = image.bytesPerLine();
|
|
269 | - bitmap.pixel_mode = aaEnabled ? FT_PIXEL_MODE_GRAY : FT_PIXEL_MODE_MONO;
|
|
270 | - |
|
271 | - FT_Error error = FT_Outline_Get_Bitmap(engine_->ftLibrary(),
|
|
272 | - &outline_,
|
|
273 | - &bitmap);
|
|
274 | - if (error)
|
|
275 | - {
|
|
276 | - // XXX error handling
|
|
277 | - return true;
|
|
278 | - }
|
|
279 | - |
|
280 | - painter->drawImage(
|
|
281 | - QPoint(x_ + cbox.xMin / 64, y_ + (-cbox.yMax / 64)),
|
|
282 | - image.convertToFormat(QImage::Format_ARGB32_Premultiplied));
|
|
251 | + painter->drawImage(offset + QPoint(x_, y_),
|
|
252 | + *image);
|
|
253 | + delete image;
|
|
283 | 254 | |
284 | 255 | x_ += width;
|
285 | -
|
|
286 | 256 | return true;
|
287 | 257 | }
|
288 | 258 | |
... | ... | @@ -290,15 +260,13 @@ GlyphContinuous::paintChar(QPainter* painter) |
290 | 260 | bool
|
291 | 261 | GlyphContinuous::loadGlyph(int index)
|
292 | 262 | {
|
263 | + if (isGlyphCloned_)
|
|
264 | + FT_Done_Glyph(glyph_);
|
|
293 | 265 | glyph_ = engine_->loadGlyphWithoutUpdate(index);
|
294 | 266 | isGlyphCloned_ = false;
|
295 | 267 | if (!glyph_)
|
296 | 268 | return false;
|
297 | - if (glyph_->format == FT_GLYPH_FORMAT_OUTLINE)
|
|
298 | - {
|
|
299 | - isOutlineCloned_ = false;
|
|
300 | - outline_ = reinterpret_cast<FT_OutlineGlyph>(glyph_)->outline;
|
|
301 | - }
|
|
269 | + refreshOutlineOrBitmapFromGlyph();
|
|
302 | 270 | return true;
|
303 | 271 | }
|
304 | 272 | |
... | ... | @@ -306,16 +274,57 @@ GlyphContinuous::loadGlyph(int index) |
306 | 274 | void
|
307 | 275 | GlyphContinuous::cloneGlyph()
|
308 | 276 | {
|
277 | + if (isGlyphCloned_)
|
|
278 | + return;
|
|
309 | 279 | glyph_ = ::cloneGlyph(glyph_);
|
280 | + refreshOutlineOrBitmapFromGlyph();
|
|
310 | 281 | isGlyphCloned_ = true;
|
311 | 282 | }
|
312 | 283 | |
313 | 284 | |
314 | 285 | void
|
315 | -GlyphContinuous::cloneOutline()
|
|
286 | +GlyphContinuous::cloneBitmap()
|
|
316 | 287 | {
|
317 | - outline_ = ::cloneOutline(engine_->ftLibrary(), &outline_);
|
|
318 | - isOutlineCloned_ = true;
|
|
288 | + if (isBitmapCloned_)
|
|
289 | + return;
|
|
290 | + bitmap_ = ::cloneBitmap(engine_->ftLibrary(), &bitmap_);
|
|
291 | + isBitmapCloned_ = true;
|
|
292 | +}
|
|
293 | + |
|
294 | + |
|
295 | +void
|
|
296 | +GlyphContinuous::refreshOutlineOrBitmapFromGlyph()
|
|
297 | +{
|
|
298 | + if (glyph_->format == FT_GLYPH_FORMAT_OUTLINE)
|
|
299 | + {
|
|
300 | + outline_ = reinterpret_cast<FT_OutlineGlyph>(glyph_)->outline;
|
|
301 | + |
|
302 | + // Make `bitmap_` invalid
|
|
303 | + if (isBitmapCloned_)
|
|
304 | + FT_Bitmap_Done(engine_->ftLibrary(), &bitmap_);
|
|
305 | + isBitmapCloned_ = false;
|
|
306 | + bitmap_.buffer = NULL;
|
|
307 | + }
|
|
308 | + else if (glyph_->format == FT_GLYPH_FORMAT_BITMAP)
|
|
309 | + {
|
|
310 | + // Initialize `bitmap_`
|
|
311 | + if (isBitmapCloned_)
|
|
312 | + FT_Bitmap_Done(engine_->ftLibrary(), &bitmap_);
|
|
313 | + isBitmapCloned_ = false;
|
|
314 | + bitmap_ = reinterpret_cast<FT_BitmapGlyph>(glyph_)->bitmap;
|
|
315 | + |
|
316 | + outline_.points = NULL;
|
|
317 | + }
|
|
318 | + else
|
|
319 | + {
|
|
320 | + // Both invalid.
|
|
321 | + outline_.points = NULL;
|
|
322 | + |
|
323 | + if (isBitmapCloned_)
|
|
324 | + FT_Bitmap_Done(engine_->ftLibrary(), &bitmap_);
|
|
325 | + isBitmapCloned_ = false;
|
|
326 | + bitmap_.buffer = NULL;
|
|
327 | + }
|
|
319 | 328 | }
|
320 | 329 | |
321 | 330 | |
... | ... | @@ -324,13 +333,17 @@ GlyphContinuous::cleanCloned() |
324 | 333 | {
|
325 | 334 | if (isGlyphCloned_)
|
326 | 335 | {
|
336 | + if (glyph_->format == FT_GLYPH_FORMAT_BITMAP && !isBitmapCloned_)
|
|
337 | + bitmap_.buffer = NULL;
|
|
338 | + |
|
327 | 339 | FT_Done_Glyph(glyph_);
|
328 | 340 | isGlyphCloned_ = false;
|
329 | 341 | }
|
330 | - if (isOutlineCloned_)
|
|
342 | + if (isBitmapCloned_)
|
|
331 | 343 | {
|
332 | - FT_Outline_Done(engine_->ftLibrary(), &outline_);
|
|
333 | - isOutlineCloned_ = false;
|
|
344 | + FT_Bitmap_Done(engine_->ftLibrary(), &bitmap_);
|
|
345 | + bitmap_.buffer = NULL;
|
|
346 | + isBitmapCloned_ = false;
|
|
334 | 347 | }
|
335 | 348 | }
|
336 | 349 |
... | ... | @@ -70,7 +70,6 @@ protected: |
70 | 70 | |
71 | 71 | private:
|
72 | 72 | Engine* engine_;
|
73 | - GraphicsDefault* graphicsDefault_;
|
|
74 | 73 | |
75 | 74 | Source source_ = SRC_AllGlyphs;
|
76 | 75 | Mode mode_ = M_Normal;
|
... | ... | @@ -88,23 +87,35 @@ private: |
88 | 87 | FT_Size_Metrics metrics_;
|
89 | 88 | int x_ = 0, y_ = 0;
|
90 | 89 | int stepY_ = 0;
|
90 | + |
|
91 | + // Pay especially attention to life cycles & ownerships of those objects:
|
|
92 | + // Note that outline and bitmap can be either invalid, owned by glyph or
|
|
93 | + // owned by `this`.
|
|
94 | + // If owned by `this`, then it's safe to do manipulation, and need to cleanup
|
|
95 | + // If owned by glyph, then must clone to do manipulation, and no cleanup
|
|
96 | + // In `loadGraph`, these 3 values will all be updated.
|
|
97 | + // Note that `glyph_` is a pointer, while `outline_` and `bitmap_` are structs
|
|
91 | 98 | FT_Glyph glyph_;
|
92 | - FT_Outline outline_;
|
|
99 | + FT_Outline outline_; // Using outline_->points == NULL to determine validity
|
|
100 | + FT_Bitmap bitmap_; // Using bitmap_->buffer == NULL to determine validity
|
|
93 | 101 | // when glyph is cloned, outline is factually also cloned
|
94 | - // but `isOutlineCloned` won't be set!
|
|
95 | - bool isGlyphCloned_ = false, isOutlineCloned_ = false;
|
|
102 | + // never manually clone your outline or you can't easily render it!
|
|
103 | + bool isGlyphCloned_ = false;
|
|
104 | + bool isBitmapCloned_ = false;
|
|
96 | 105 | |
97 | 106 | FT_Stroker stroker_;
|
98 | 107 | |
99 | 108 | void paintAG(QPainter* painter);
|
100 | - void transformGlyphAGFancy();
|
|
101 | - void transformGlyphAGStroked();
|
|
109 | + void transformGlyphFancy();
|
|
110 | + void transformGlyphStroked();
|
|
102 | 111 | void prePaint();
|
103 | 112 | // return if there's enough space to paint the current char
|
104 | 113 | bool paintChar(QPainter* painter);
|
105 | 114 | bool loadGlyph(int index);
|
115 | + |
|
106 | 116 | void cloneGlyph();
|
107 | - void cloneOutline();
|
|
117 | + void cloneBitmap();
|
|
118 | + void refreshOutlineOrBitmapFromGlyph();
|
|
108 | 119 | void cleanCloned();
|
109 | 120 | |
110 | 121 | bool checkFitX(int x);
|
... | ... | @@ -25,6 +25,19 @@ cloneGlyph(FT_Glyph src) |
25 | 25 | }
|
26 | 26 | |
27 | 27 | |
28 | +FT_Bitmap
|
|
29 | +cloneBitmap(FT_Library library,
|
|
30 | + FT_Bitmap* src)
|
|
31 | +{
|
|
32 | + FT_Bitmap target = *src;
|
|
33 | + target.buffer = NULL;
|
|
34 | + target.palette = NULL;
|
|
35 | + FT_Bitmap_Init(&target);
|
|
36 | + FT_Bitmap_Copy(library, src, &target);
|
|
37 | + return target;
|
|
38 | +}
|
|
39 | + |
|
40 | + |
|
28 | 41 | void
|
29 | 42 | transformOutlineToOrigin(FT_Outline* outline,
|
30 | 43 | FT_BBox* outControlBox)
|
... | ... | @@ -5,11 +5,13 @@ |
5 | 5 | #pragma once
|
6 | 6 | |
7 | 7 | #include <freetype/ftglyph.h>
|
8 | +#include <freetype/ftbitmap.h>
|
|
8 | 9 | #include <freetype/ftoutln.h>
|
9 | 10 | |
10 | 11 | // The constructed `outline` must be freed by the caller
|
11 | 12 | FT_Outline cloneOutline(FT_Library library, FT_Outline* src);
|
12 | 13 | FT_Glyph cloneGlyph(FT_Glyph src);
|
14 | +FT_Bitmap cloneBitmap(FT_Library library, FT_Bitmap* src);
|
|
13 | 15 | |
14 | 16 | void transformOutlineToOrigin(FT_Outline* outline,
|
15 | 17 | FT_BBox* outControlBox);
|