Commits:
-
bb053ffd
by Charlie Jiang
at 2022-07-14T16:08:10+08:00
[ftinspect] Add Fancy submode to "Continuous View"
Fancy mode adds slanting and hori./vert. emboldening to the glyph.
`GlyphContinuous::paintChar` is broken down to better support additional
operations during rendering. Add proper cloning so the glyph and the
outline which are stored in the `GlyphContinuous` class can be safely
modified.
* src/ftinspect/rendering/glyphcontinuous.cpp,
src/ftinspect/rendering/glyphcontinuous.hpp: As described, refactored and
supported Fancy mode.
* src/ftinspect/rendering/glyphbitmap.cpp: Edited to match the new
`renderutils.cpp`.
* src/ftinspect/rendering/renderutils.cpp,
src/ftinspect/rendering/renderutils.hpp: Broken down
`transformOutlineToOrigin`, add `cloneOutline` and `cloneGlyph`.
* src/ftinspect/panels/continuous.cpp, src/ftinspect/panels/continuous.hpp:
Add necessary GUI components and data passing to support fancy mode.
-
e6c47fa6
by Charlie Jiang
at 2022-07-14T16:08:10+08:00
[ftinspect] Support Stroked SubMode in "Continuous Mode"
* src/ftinspect/panels/continuous.cpp, src/ftinspect/panels/continuous.hpp:
GUI update.
* src/ftinspect/rendering/glyphcontinuous.cpp,
src/ftinspect/rendering/glyphcontinuous.hpp: Add support.
-
b1392d6a
by Charlie Jiang
at 2022-07-14T16:08:10+08:00
* src/ftinspect/meson.build: Fix meson build.
Fix typo.
-
ed68c568
by Charlie Jiang
at 2022-07-14T16:08:10+08:00
[ftinspect] Fix compilation on GCC.
* src/ftinspect/panels/continuous.hpp, src/ftinspect/panels/continuous.cpp,
use `std::vector` over `QVector` because the latter requires default
`constructor`; Fix signedness because of `std::vector`;
* src/ftinspect/models/ttsettingscomboboxmodel.hpp: Fix enum inconsistency.
* src/ftinspect/engine/engine.hpp, src/ftinspect/engine/engine.cpp: Fix
missing include; use `std::vector`;
* src/ftinspect/CMakeLists.txt: Fix MinGW: g++ doesn't need `/utf-8` switch.
-
f532d57c
by Charlie Jiang
at 2022-07-14T16:08:10+08:00
[ftinspect] Remove redundant text on the GUI.
Removed "Count:" indicator showing the display count because it serves
little value. Removed "for Fancy/Stroked" text from the label because
graying out elements is already enough.
* src/ftinspect/panels/continuous.cpp: Remove "Count:" indicator.
* src/ftinspect/widgets/glyphindexselector.cpp: Remove text from label.
-
1e38831a
by Charlie Jiang
at 2022-07-14T16:08:10+08:00
[ftinspect] Support embedded bitmap, refactor rendering.
This commit supported embedded bitmap and more FreeType font types. Singular
rendering widgets are refactored so they're more flexible about glyph and
bitmap types.
Replace `loadOutline` in `Engine` to `loadGlyph` and add other glyph
formats. Move the rasterization from `GlyphBitmap` to `Engine` to decouple
rendering from specific widgets. Engine will produce `QImage` object so
render widgets can be agnostic about glyph type.
Added "Enable Embedded Bitmap" checkbox to the GUI, so one can still force
disable embedded bitmap output. Outline, points and point numbers showing
are hidden when the glyph format isn't outline.
LCD rendering is not yet supported because `convertLCDToARGB` and
`convertLCDVToARGB` are not implemented.
* src/ftinspect/engine/engine.cpp, src/ftinspect/engine/engine.hpp:
Replace `loadOutline` to `loadGlyph`, and enable non-outline glyph types.
Add `glyphToBitmap`, `convertBitmapTo8Bpp` and `convertBitmapToQImage`.
Add necessary setting properties.
TODO: Move `glyphFormatToName` and CharMap related code out from
`engine.[ch]pp`.
* src/ftinspect/rendering/glyphbitmap.cpp,
src/ftinspect/rendering/glyphbitmap.hpp:
Remove detailed rasterizing code, and use `Engine` to generate `QImage`..
* src/ftinspect/panels/singular.cpp: Use `loadGlyph` instead of
`loadOutline`, and remove code about pixel mode.
* src/ftinspect/models/ttsettingscomboboxmodel.cpp,
src/ftinspect/models/ttsettingscomboboxmodel.hpp:
Make `SimpleComboBoxModel` a template class because the Anti-Aliasing
setting combo box maps to multiple fields (load flag, render mode and
RGB/BGR).
Because Qt disallows template class with Q_OBJECT, we have to use mixin
instead of inheritance. The new base class is named
`SimpleComboBoxModelImpl` and subclass delegate function calls to it.
Those models may subject to refactoring later.
* src/ftinspect/rendering/renderutils.cpp,
src/ftinspect/rendering/renderutils.hpp:
Split `computeTransformationToOrigin` out from `transformOutlineToOrigin`.
* src/ftinspect/rendering/glyphoutline.cpp,
src/ftinspect/rendering/glyphoutline.hpp,
src/ftinspect/rendering/glyphpoints.cpp,
src/ftinspect/rendering/glyphpoints.hpp,
src/ftinspect/rendering/glyphpointnumbers.cpp,
src/ftinspect/rendering/glyphpointnumbers.hpp:
Receive `FT_Glyph` instead of `FT_Outline*` as input, but don't preceed if
the glyph isn't outline-typed.
-
598ce364
by Charlie Jiang
at 2022-07-14T16:08:10+08:00
[ftinspect] Rename `ttsettingscomboboxmodel.[ch]pp`.
Rename them to `customcomboboxmodels.[ch]pp`.
* src/ftinspect/CMakeLists.txt, src/ftinspect/meson.build: Updated.
25 changed files:
Changes:
src/ftinspect/CMakeLists.txt
... |
... |
@@ -4,7 +4,7 @@ set(CMAKE_CXX_STANDARD 11) |
4
|
4
|
|
5
|
5
|
project("ftinspect")
|
6
|
6
|
|
7
|
|
-if (WIN32)
|
|
7
|
+if (MSVC)
|
8
|
8
|
add_compile_options("/utf-8")
|
9
|
9
|
endif ()
|
10
|
10
|
|
... |
... |
@@ -36,7 +36,7 @@ add_executable(ftinspect |
36
|
36
|
"widgets/glyphindexselector.cpp"
|
37
|
37
|
"widgets/fontsizeselector.cpp"
|
38
|
38
|
|
39
|
|
- "models/ttsettingscomboboxmodel.cpp"
|
|
39
|
+ "models/customcomboboxmodels.cpp"
|
40
|
40
|
|
41
|
41
|
"panels/settingpanel.cpp"
|
42
|
42
|
"panels/singular.cpp"
|
src/ftinspect/engine/engine.cpp
... |
... |
@@ -5,12 +5,16 @@ |
5
|
5
|
|
6
|
6
|
#include "engine.hpp"
|
7
|
7
|
|
|
8
|
+#include "../rendering/renderutils.hpp"
|
|
9
|
+#include "../rendering/graphicsdefault.hpp"
|
|
10
|
+
|
8
|
11
|
#include <stdexcept>
|
9
|
12
|
#include <stdint.h>
|
10
|
13
|
|
11
|
14
|
#include <freetype/ftmodapi.h>
|
12
|
15
|
#include <freetype/ftdriver.h>
|
13
|
16
|
#include <freetype/ftlcdfil.h>
|
|
17
|
+#include <freetype/ftbitmap.h>
|
14
|
18
|
|
15
|
19
|
|
16
|
20
|
/////////////////////////////////////////////////////////////////////////////
|
... |
... |
@@ -153,7 +157,7 @@ Engine::Engine() |
153
|
157
|
{
|
154
|
158
|
// XXX error handling
|
155
|
159
|
}
|
156
|
|
-
|
|
160
|
+
|
157
|
161
|
queryEngine();
|
158
|
162
|
}
|
159
|
163
|
|
... |
... |
@@ -309,7 +313,7 @@ Engine::loadFont(int fontIndex, |
309
|
313
|
curCharMaps_.clear();
|
310
|
314
|
curCharMaps_.reserve(face->num_charmaps);
|
311
|
315
|
for (int i = 0; i < face->num_charmaps; i++)
|
312
|
|
- curCharMaps_.append(CharMapInfo(i, face->charmaps[i]));
|
|
316
|
+ curCharMaps_.emplace_back(i, face->charmaps[i]);
|
313
|
317
|
}
|
314
|
318
|
|
315
|
319
|
curNumGlyphs_ = numGlyphs;
|
... |
... |
@@ -397,8 +401,8 @@ Engine::glyphName(int index) |
397
|
401
|
}
|
398
|
402
|
|
399
|
403
|
|
400
|
|
-FT_Outline*
|
401
|
|
-Engine::loadOutline(int glyphIndex)
|
|
404
|
+FT_Glyph
|
|
405
|
+Engine::loadGlyph(int glyphIndex)
|
402
|
406
|
{
|
403
|
407
|
update();
|
404
|
408
|
|
... |
... |
@@ -407,13 +411,11 @@ Engine::loadOutline(int glyphIndex) |
407
|
411
|
|
408
|
412
|
FT_Glyph glyph;
|
409
|
413
|
|
410
|
|
- // XXX handle bitmap fonts
|
411
|
|
-
|
412
|
414
|
// the `scaler' object is set up by the
|
413
|
415
|
// `update' and `loadFont' methods
|
414
|
416
|
if (FTC_ImageCache_LookupScaler(imageCache_,
|
415
|
417
|
&scaler_,
|
416
|
|
- loadFlags_ | FT_LOAD_NO_BITMAP,
|
|
418
|
+ loadFlags_,
|
417
|
419
|
static_cast<unsigned int>(glyphIndex),
|
418
|
420
|
&glyph,
|
419
|
421
|
NULL))
|
... |
... |
@@ -422,21 +424,14 @@ Engine::loadOutline(int glyphIndex) |
422
|
424
|
return NULL;
|
423
|
425
|
}
|
424
|
426
|
|
425
|
|
- if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
426
|
|
- return NULL;
|
427
|
|
-
|
428
|
|
- FT_OutlineGlyph outlineGlyph = reinterpret_cast<FT_OutlineGlyph>(glyph);
|
429
|
|
-
|
430
|
|
- return &outlineGlyph->outline;
|
|
427
|
+ return glyph;
|
431
|
428
|
}
|
432
|
429
|
|
433
|
430
|
|
434
|
431
|
FT_Glyph
|
435
|
432
|
Engine::loadGlyphWithoutUpdate(int glyphIndex)
|
436
|
433
|
{
|
437
|
|
- // TODO bitmap fonts? color layered fonts?
|
438
|
434
|
FT_Glyph glyph;
|
439
|
|
- imageType_.flags |= FT_LOAD_NO_BITMAP;
|
440
|
435
|
if (FTC_ImageCache_Lookup(imageCache_,
|
441
|
436
|
&imageType_,
|
442
|
437
|
glyphIndex,
|
... |
... |
@@ -451,6 +446,57 @@ Engine::loadGlyphWithoutUpdate(int glyphIndex) |
451
|
446
|
}
|
452
|
447
|
|
453
|
448
|
|
|
449
|
+bool
|
|
450
|
+Engine::glyphToBitmap(FT_Glyph src,
|
|
451
|
+ FT_Glyph* out)
|
|
452
|
+{
|
|
453
|
+ if (src->format == FT_GLYPH_FORMAT_BITMAP)
|
|
454
|
+ {
|
|
455
|
+ *out = src;
|
|
456
|
+ return false;
|
|
457
|
+ }
|
|
458
|
+ if (src->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
459
|
+ {
|
|
460
|
+ *out = NULL;
|
|
461
|
+ return false;
|
|
462
|
+ // TODO support SVG
|
|
463
|
+ }
|
|
464
|
+
|
|
465
|
+ if (src->format == FT_GLYPH_FORMAT_OUTLINE)
|
|
466
|
+ {
|
|
467
|
+ FT_Glyph out2 = src;
|
|
468
|
+ auto error = FT_Glyph_To_Bitmap(&out2,
|
|
469
|
+ static_cast<FT_Render_Mode>(renderMode_),
|
|
470
|
+ nullptr,
|
|
471
|
+ false);
|
|
472
|
+ if (error)
|
|
473
|
+ {
|
|
474
|
+ *out = NULL;
|
|
475
|
+ return false;
|
|
476
|
+ }
|
|
477
|
+ *out = out2;
|
|
478
|
+ return true;
|
|
479
|
+ }
|
|
480
|
+
|
|
481
|
+ *out = NULL;
|
|
482
|
+ return false;
|
|
483
|
+}
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+FT_Bitmap
|
|
487
|
+Engine::convertBitmapTo8Bpp(FT_Bitmap* bitmap)
|
|
488
|
+{
|
|
489
|
+ FT_Bitmap out;
|
|
490
|
+ out.buffer = NULL;
|
|
491
|
+ auto error = FT_Bitmap_Convert(library_, bitmap, &out, 1);
|
|
492
|
+ if (error)
|
|
493
|
+ {
|
|
494
|
+ // XXX handling?
|
|
495
|
+ }
|
|
496
|
+ return out;
|
|
497
|
+}
|
|
498
|
+
|
|
499
|
+
|
454
|
500
|
int
|
455
|
501
|
Engine::numberOfOpenedFonts()
|
456
|
502
|
{
|
... |
... |
@@ -527,19 +573,19 @@ Engine::update() |
527
|
573
|
loadFlags_ = FT_LOAD_DEFAULT;
|
528
|
574
|
if (doAutoHinting_)
|
529
|
575
|
loadFlags_ |= FT_LOAD_FORCE_AUTOHINT;
|
530
|
|
- loadFlags_ |= FT_LOAD_NO_BITMAP; // XXX handle bitmap fonts also
|
|
576
|
+
|
|
577
|
+ if (!embeddedBitmap_)
|
|
578
|
+ loadFlags_ |= FT_LOAD_NO_BITMAP;
|
531
|
579
|
|
532
|
580
|
if (doHinting_)
|
533
|
581
|
{
|
534
|
|
- // TODO Differentiate RGB/BGR here?
|
535
|
|
- unsigned long target = antiAliasingTarget_;
|
536
|
|
- loadFlags_ |= target;
|
|
582
|
+ loadFlags_ |= antiAliasingTarget_;
|
537
|
583
|
}
|
538
|
584
|
else
|
539
|
585
|
{
|
540
|
586
|
loadFlags_ |= FT_LOAD_NO_HINTING;
|
541
|
587
|
|
542
|
|
- if (!antiAliasingEnabled_) // XXX does this hold?
|
|
588
|
+ if (!antiAliasingEnabled_)
|
543
|
589
|
loadFlags_ |= FT_LOAD_MONOCHROME;
|
544
|
590
|
}
|
545
|
591
|
|
... |
... |
@@ -561,7 +607,7 @@ Engine::update() |
561
|
607
|
scaler_.x_res = dpi_;
|
562
|
608
|
scaler_.y_res = dpi_;
|
563
|
609
|
}
|
564
|
|
-
|
|
610
|
+
|
565
|
611
|
imageType_.width = static_cast<unsigned int>(pixelSize_);
|
566
|
612
|
imageType_.height = static_cast<unsigned int>(pixelSize_);
|
567
|
613
|
imageType_.flags = static_cast<int>(loadFlags_);
|
... |
... |
@@ -668,6 +714,149 @@ Engine::queryEngine() |
668
|
714
|
}
|
669
|
715
|
|
670
|
716
|
|
|
717
|
+void
|
|
718
|
+convertLCDToARGB(FT_Bitmap& bitmap,
|
|
719
|
+ QImage& image,
|
|
720
|
+ bool isBGR)
|
|
721
|
+{
|
|
722
|
+ // TODO to be implemented
|
|
723
|
+}
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+void
|
|
727
|
+convertLCDVToARGB(FT_Bitmap& bitmap,
|
|
728
|
+ QImage& image,
|
|
729
|
+ bool isBGR)
|
|
730
|
+{
|
|
731
|
+ // TODO to be implemented
|
|
732
|
+}
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+QImage*
|
|
736
|
+Engine::convertBitmapToQImage(FT_Glyph src,
|
|
737
|
+ QRect* outRect)
|
|
738
|
+{
|
|
739
|
+ QImage* result = NULL;
|
|
740
|
+ FT_BitmapGlyph bitmapGlyph;
|
|
741
|
+ bool ownBitmapGlyph
|
|
742
|
+ = glyphToBitmap(src, reinterpret_cast<FT_Glyph*>(&bitmapGlyph));
|
|
743
|
+ if (!bitmapGlyph)
|
|
744
|
+ return result;
|
|
745
|
+ auto& bmap = bitmapGlyph->bitmap;
|
|
746
|
+ bool ownBitmap = false;
|
|
747
|
+
|
|
748
|
+ int width = bmap.width;
|
|
749
|
+ int height = bmap.rows;
|
|
750
|
+ QImage::Format format = QImage::Format_Indexed8; // goto crossing init
|
|
751
|
+
|
|
752
|
+ if (bmap.pixel_mode == FT_PIXEL_MODE_GRAY2
|
|
753
|
+ || bmap.pixel_mode == FT_PIXEL_MODE_GRAY4)
|
|
754
|
+ {
|
|
755
|
+ bmap = convertBitmapTo8Bpp(&bmap);
|
|
756
|
+ if (!bmap.buffer)
|
|
757
|
+ goto cleanup;
|
|
758
|
+ ownBitmap = true;
|
|
759
|
+ }
|
|
760
|
+
|
|
761
|
+ if (bmap.pixel_mode == FT_PIXEL_MODE_LCD)
|
|
762
|
+ width /= 3;
|
|
763
|
+ else if (bmap.pixel_mode == FT_PIXEL_MODE_LCD_V)
|
|
764
|
+ height /= 3;
|
|
765
|
+
|
|
766
|
+ if (outRect)
|
|
767
|
+ {
|
|
768
|
+ outRect->setLeft(bitmapGlyph->left);
|
|
769
|
+ outRect->setTop(-bitmapGlyph->top);
|
|
770
|
+ outRect->setWidth(width);
|
|
771
|
+ outRect->setHeight(height);
|
|
772
|
+ }
|
|
773
|
+
|
|
774
|
+ switch (bmap.pixel_mode)
|
|
775
|
+ {
|
|
776
|
+ case FT_PIXEL_MODE_MONO:
|
|
777
|
+ format = QImage::Format_Mono;
|
|
778
|
+ break;
|
|
779
|
+ case FT_PIXEL_MODE_GRAY:
|
|
780
|
+ format = QImage::Format_Indexed8;
|
|
781
|
+ break;
|
|
782
|
+ case FT_PIXEL_MODE_BGRA:
|
|
783
|
+ // XXX "ARGB" here means BGRA due to endianness - may be problematic
|
|
784
|
+ // on big-endian machines
|
|
785
|
+ format = QImage::Format_ARGB32_Premultiplied;
|
|
786
|
+ break;
|
|
787
|
+ case FT_PIXEL_MODE_LCD:
|
|
788
|
+ case FT_PIXEL_MODE_LCD_V:
|
|
789
|
+ format = QImage::Format_ARGB32;
|
|
790
|
+ break;
|
|
791
|
+ default:
|
|
792
|
+ goto cleanup;
|
|
793
|
+ }
|
|
794
|
+
|
|
795
|
+ switch (bmap.pixel_mode)
|
|
796
|
+ {
|
|
797
|
+ case FT_PIXEL_MODE_MONO:
|
|
798
|
+ case FT_PIXEL_MODE_GRAY:
|
|
799
|
+ case FT_PIXEL_MODE_BGRA:
|
|
800
|
+ {
|
|
801
|
+ QImage image(bmap.buffer,
|
|
802
|
+ width, height,
|
|
803
|
+ bmap.pitch,
|
|
804
|
+ format);
|
|
805
|
+ if (bmap.pixel_mode == FT_PIXEL_MODE_GRAY)
|
|
806
|
+ image.setColorTable(GraphicsDefault::deafultInstance()->grayColorTable);
|
|
807
|
+ else if (bmap.pixel_mode == FT_PIXEL_MODE_MONO)
|
|
808
|
+ image.setColorTable(GraphicsDefault::deafultInstance()->monoColorTable);
|
|
809
|
+ result = new QImage(image.copy());
|
|
810
|
+ // Don't directly use `image` since we're destroying the image
|
|
811
|
+ }
|
|
812
|
+ break;
|
|
813
|
+ case FT_PIXEL_MODE_LCD:;
|
|
814
|
+ result = new QImage(width, height, format);
|
|
815
|
+ convertLCDToARGB(bmap, *result, lcdUsesBGR_);
|
|
816
|
+ break;
|
|
817
|
+ case FT_PIXEL_MODE_LCD_V:;
|
|
818
|
+ result = new QImage(width, height, format);
|
|
819
|
+ convertLCDVToARGB(bmap, *result, lcdUsesBGR_);
|
|
820
|
+ break;
|
|
821
|
+ }
|
|
822
|
+
|
|
823
|
+cleanup:
|
|
824
|
+ if (ownBitmapGlyph)
|
|
825
|
+ FT_Done_Glyph(reinterpret_cast<FT_Glyph>(bitmapGlyph));
|
|
826
|
+ if (ownBitmap)
|
|
827
|
+ FT_Bitmap_Done(library_, &bmap);
|
|
828
|
+
|
|
829
|
+ return result;
|
|
830
|
+}
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+QHash<FT_Glyph_Format, QString> glyphFormatNamesCache;
|
|
834
|
+QHash<FT_Glyph_Format, QString>&
|
|
835
|
+glyphFormatNames()
|
|
836
|
+{
|
|
837
|
+ if (glyphFormatNamesCache.empty())
|
|
838
|
+ {
|
|
839
|
+ glyphFormatNamesCache[FT_GLYPH_FORMAT_NONE] = "None/Unknown";
|
|
840
|
+ glyphFormatNamesCache[FT_GLYPH_FORMAT_COMPOSITE] = "Composite";
|
|
841
|
+ glyphFormatNamesCache[FT_GLYPH_FORMAT_BITMAP] = "Bitmap";
|
|
842
|
+ glyphFormatNamesCache[FT_GLYPH_FORMAT_OUTLINE] = "Outline";
|
|
843
|
+ glyphFormatNamesCache[FT_GLYPH_FORMAT_PLOTTER] = "Plotter";
|
|
844
|
+ glyphFormatNamesCache[FT_GLYPH_FORMAT_SVG] = "SVG";
|
|
845
|
+ }
|
|
846
|
+ return glyphFormatNamesCache;
|
|
847
|
+}
|
|
848
|
+
|
|
849
|
+QString*
|
|
850
|
+glyphFormatToName(FT_Glyph_Format format)
|
|
851
|
+{
|
|
852
|
+ auto& names = glyphFormatNames();
|
|
853
|
+ auto it = names.find(format);
|
|
854
|
+ if (it == names.end())
|
|
855
|
+ return &names[FT_GLYPH_FORMAT_NONE];
|
|
856
|
+ return &it.value();
|
|
857
|
+}
|
|
858
|
+
|
|
859
|
+
|
671
|
860
|
QHash<FT_Encoding, QString> encodingNamesCache;
|
672
|
861
|
QHash<FT_Encoding, QString>&
|
673
|
862
|
encodingNames()
|
src/ftinspect/engine/engine.hpp
... |
... |
@@ -7,8 +7,11 @@ |
7
|
7
|
|
8
|
8
|
#include "fontfilemanager.hpp"
|
9
|
9
|
|
|
10
|
+#include <vector>
|
10
|
11
|
#include <QString>
|
11
|
12
|
#include <QMap>
|
|
13
|
+#include <QRect>
|
|
14
|
+#include <QImage>
|
12
|
15
|
|
13
|
16
|
#include <ft2build.h>
|
14
|
17
|
#include <freetype/freetype.h>
|
... |
... |
@@ -59,6 +62,10 @@ private: |
59
|
62
|
static int maxIndexForFaceAndCharMap(FT_CharMap charMap, unsigned max);
|
60
|
63
|
};
|
61
|
64
|
|
|
65
|
+// Some helper functions.
|
|
66
|
+
|
|
67
|
+QString* glyphFormatToName(FT_Glyph_Format format);
|
|
68
|
+
|
62
|
69
|
// FreeType specific data.
|
63
|
70
|
|
64
|
71
|
class Engine
|
... |
... |
@@ -91,11 +98,17 @@ public: |
91
|
98
|
int loadFont(int fontIndex,
|
92
|
99
|
long faceIndex,
|
93
|
100
|
int namedInstanceIndex); // return number of glyphs
|
94
|
|
- FT_Outline* loadOutline(int glyphIndex);
|
|
101
|
+ FT_Glyph loadGlyph(int glyphIndex);
|
95
|
102
|
|
96
|
103
|
// Sometimes the engine is already updated, and we want to be faster
|
97
|
104
|
FT_Glyph loadGlyphWithoutUpdate(int glyphIndex);
|
98
|
105
|
|
|
106
|
+ // Return `true` if you need to free `out`
|
|
107
|
+ // `out` will be set to NULL in cases of error
|
|
108
|
+ bool glyphToBitmap(FT_Glyph src, FT_Glyph* out);
|
|
109
|
+ FT_Bitmap convertBitmapTo8Bpp(FT_Bitmap* bitmap);
|
|
110
|
+ QImage* convertBitmapToQImage(FT_Glyph src, QRect* outRect);
|
|
111
|
+
|
99
|
112
|
// reload current triplet, but with updated settings, useful for updating
|
100
|
113
|
// `ftSize_` only
|
101
|
114
|
void reloadFont();
|
... |
... |
@@ -121,11 +134,11 @@ public: |
121
|
134
|
unsigned glyphIndexFromCharCode(int code, int charMapIndex);
|
122
|
135
|
FT_Size_Metrics const& currentFontMetrics();
|
123
|
136
|
|
124
|
|
- QVector<CharMapInfo>& currentFontCharMaps() { return curCharMaps_; }
|
|
137
|
+ std::vector<CharMapInfo>& currentFontCharMaps() { return curCharMaps_; }
|
125
|
138
|
FontFileManager& fontFileManager() { return fontFileManager_; }
|
126
|
139
|
EngineDefaultValues& engineDefaults() { return engineDefaults_; }
|
127
|
140
|
bool antiAliasingEnabled() { return antiAliasingEnabled_; }
|
128
|
|
-
|
|
141
|
+ bool embeddedBitmapEnabled() { return embeddedBitmap_; }
|
129
|
142
|
|
130
|
143
|
//////// Setters (direct or indirect)
|
131
|
144
|
|
... |
... |
@@ -149,7 +162,10 @@ public: |
149
|
162
|
void setShowSegments(bool showSegments) { showSegments_ = showSegments; }
|
150
|
163
|
void setGamma(double gamma) { gamma_ = gamma; }
|
151
|
164
|
void setAntiAliasingTarget(int target) { antiAliasingTarget_ = target; }
|
|
165
|
+ void setRenderMode(int mode) { renderMode_ = mode; }
|
152
|
166
|
void setAntiAliasingEnabled(bool enabled) { antiAliasingEnabled_ = enabled; }
|
|
167
|
+ void setEmbeddedBitmap(bool force) { embeddedBitmap_ = force; }
|
|
168
|
+ void setLCDUsesBGR(bool isBGR) { lcdUsesBGR_ = isBGR; }
|
153
|
169
|
|
154
|
170
|
// Note: These 3 functions now takes actual mode/version from FreeType,
|
155
|
171
|
// instead of values from enum in MainGUI!
|
... |
... |
@@ -174,7 +190,7 @@ private: |
174
|
190
|
QString curFamilyName_;
|
175
|
191
|
QString curStyleName_;
|
176
|
192
|
int curNumGlyphs_ = -1;
|
177
|
|
- QVector<CharMapInfo> curCharMaps_;
|
|
193
|
+ std::vector<CharMapInfo> curCharMaps_;
|
178
|
194
|
|
179
|
195
|
FT_Library library_;
|
180
|
196
|
FTC_Manager cacheManager_;
|
... |
... |
@@ -202,10 +218,12 @@ private: |
202
|
218
|
bool doVerticalHinting_;
|
203
|
219
|
bool doBlueZoneHinting_;
|
204
|
220
|
bool showSegments_;
|
|
221
|
+ bool embeddedBitmap_;
|
205
|
222
|
int antiAliasingTarget_;
|
|
223
|
+ bool lcdUsesBGR_;
|
|
224
|
+ int renderMode_;
|
206
|
225
|
|
207
|
226
|
double gamma_;
|
208
|
|
-
|
209
|
227
|
unsigned long loadFlags_;
|
210
|
228
|
|
211
|
229
|
void queryEngine();
|
src/ftinspect/meson.build
... |
... |
@@ -35,7 +35,7 @@ if qt5_dep.found() |
35
|
35
|
'widgets/glyphindexselector.cpp',
|
36
|
36
|
'widgets/fontsizeselector.cpp',
|
37
|
37
|
|
38
|
|
- 'models/ttsettingscomboboxmodel.cpp',
|
|
38
|
+ 'models/customcomboboxmodels.cpp',
|
39
|
39
|
|
40
|
40
|
'panels/settingpanel.cpp',
|
41
|
41
|
'panels/singular.cpp',
|
... |
... |
@@ -52,7 +52,7 @@ if qt5_dep.found() |
52
|
52
|
'widgets/customwidgets.hpp',
|
53
|
53
|
'widgets/glyphindexselector.hpp',
|
54
|
54
|
'widgets/fontsizeselector.hpp',
|
55
|
|
- 'widgets/glyphcontinuous.hpp',
|
|
55
|
+ 'rendering/glyphcontinuous.hpp',
|
56
|
56
|
'models/ttsettingscomboboxmodel.hpp',
|
57
|
57
|
'panels/settingpanel.hpp',
|
58
|
58
|
'panels/singular.hpp',
|
src/ftinspect/models/ttsettingscomboboxmodel.cpp
→
src/ftinspect/models/customcomboboxmodels.cpp
... |
... |
@@ -190,48 +190,6 @@ HintingModeComboBoxModel::setCurrentEngineType(HintingEngineType type) |
190
|
190
|
}
|
191
|
191
|
|
192
|
192
|
|
193
|
|
-/////////////////////////////////////////////////////////////////////////////
|
194
|
|
-//
|
195
|
|
-// SimpleComboBoxModel
|
196
|
|
-//
|
197
|
|
-/////////////////////////////////////////////////////////////////////////////
|
198
|
|
-
|
199
|
|
-
|
200
|
|
-SimpleComboBoxModel::SimpleComboBoxModel(QObject* parent)
|
201
|
|
-: QAbstractListModel(parent)
|
202
|
|
-{
|
203
|
|
-}
|
204
|
|
-
|
205
|
|
-
|
206
|
|
-int
|
207
|
|
-SimpleComboBoxModel::rowCount(const QModelIndex& parent) const
|
208
|
|
-{
|
209
|
|
- return items_.size();
|
210
|
|
-}
|
211
|
|
-
|
212
|
|
-
|
213
|
|
-QVariant
|
214
|
|
-SimpleComboBoxModel::data(const QModelIndex& index, int role) const
|
215
|
|
-{
|
216
|
|
- if (role != Qt::DisplayRole)
|
217
|
|
- return QVariant {};
|
218
|
|
-
|
219
|
|
- int r = index.row();
|
220
|
|
- if (r < 0 || r >= items_.size())
|
221
|
|
- return QVariant {};
|
222
|
|
- return items_[r].displayName;
|
223
|
|
-}
|
224
|
|
-
|
225
|
|
-
|
226
|
|
-int
|
227
|
|
-SimpleComboBoxModel::indexToValue(int index)
|
228
|
|
-{
|
229
|
|
- if (index < 0 || index >= items_.size())
|
230
|
|
- return -1;
|
231
|
|
- return items_[index].value;
|
232
|
|
-}
|
233
|
|
-
|
234
|
|
-
|
235
|
193
|
/////////////////////////////////////////////////////////////////////////////
|
236
|
194
|
//
|
237
|
195
|
// LCDFilterComboBoxModel
|
... |
... |
@@ -240,7 +198,7 @@ SimpleComboBoxModel::indexToValue(int index) |
240
|
198
|
|
241
|
199
|
|
242
|
200
|
LCDFilterComboBoxModel::LCDFilterComboBoxModel(QObject* parent)
|
243
|
|
-: SimpleComboBoxModel(parent)
|
|
201
|
+: QAbstractListModel(parent)
|
244
|
202
|
{
|
245
|
203
|
items_[LCDFilter_Default] = {
|
246
|
204
|
FT_LCD_FILTER_DEFAULT,
|
... |
... |
@@ -269,34 +227,34 @@ LCDFilterComboBoxModel::LCDFilterComboBoxModel(QObject* parent) |
269
|
227
|
|
270
|
228
|
|
271
|
229
|
AntiAliasingComboBoxModel::AntiAliasingComboBoxModel(QObject* parent)
|
272
|
|
-: SimpleComboBoxModel(parent)
|
|
230
|
+: QAbstractListModel(parent)
|
273
|
231
|
{
|
274
|
232
|
items_[AntiAliasing_None] = {
|
275
|
|
- FT_LOAD_TARGET_MONO,
|
|
233
|
+ {FT_LOAD_TARGET_MONO, FT_RENDER_MODE_MONO, false},
|
276
|
234
|
"None"
|
277
|
235
|
};
|
278
|
236
|
items_[AntiAliasing_Normal] = {
|
279
|
|
- FT_LOAD_TARGET_NORMAL,
|
|
237
|
+ {FT_LOAD_TARGET_NORMAL, FT_RENDER_MODE_NORMAL, false},
|
280
|
238
|
"Normal"
|
281
|
239
|
};
|
282
|
240
|
items_[AntiAliasing_Light] = {
|
283
|
|
- FT_LOAD_TARGET_LIGHT,
|
|
241
|
+ {FT_LOAD_TARGET_LIGHT, FT_RENDER_MODE_LIGHT, false},
|
284
|
242
|
"Light"
|
285
|
243
|
};
|
286
|
244
|
items_[AntiAliasing_LCD] = {
|
287
|
|
- FT_LOAD_TARGET_LCD,
|
|
245
|
+ {FT_LOAD_TARGET_LCD, FT_RENDER_MODE_LCD, false},
|
288
|
246
|
"LCD (RGB)"
|
289
|
247
|
};
|
290
|
248
|
items_[AntiAliasing_LCD_BGR] = {
|
291
|
|
- FT_LOAD_TARGET_LCD,
|
|
249
|
+ {FT_LOAD_TARGET_LCD, FT_RENDER_MODE_LCD, true},
|
292
|
250
|
"LCD (BGR)"
|
293
|
251
|
};
|
294
|
252
|
items_[AntiAliasing_LCD_Vertical] = {
|
295
|
|
- FT_LOAD_TARGET_LCD_V,
|
|
253
|
+ {FT_LOAD_TARGET_LCD_V, FT_RENDER_MODE_LCD_V, false},
|
296
|
254
|
"LCD (vert. RGB)"
|
297
|
255
|
};
|
298
|
256
|
items_[AntiAliasing_LCD_Vertical_BGR] = {
|
299
|
|
- FT_LOAD_TARGET_LCD_V, // XXX Bug: No difference between RGB and BGR?
|
|
257
|
+ {FT_LOAD_TARGET_LCD_V, FT_RENDER_MODE_LCD_V, true},
|
300
|
258
|
"LCD (vert. BGR)"
|
301
|
259
|
};
|
302
|
260
|
|
... |
... |
@@ -312,7 +270,7 @@ AntiAliasingComboBoxModel::data(const QModelIndex& index, |
312
|
270
|
if (index.row() == AntiAliasing_Light && !lightAntiAliasingEnabled_)
|
313
|
271
|
return QApplication::palette().color(QPalette::Disabled,
|
314
|
272
|
QPalette::Text);
|
315
|
|
- return SimpleComboBoxModel::data(index, role);
|
|
273
|
+ return SimpleComboBoxModelImpl::data(index, role);
|
316
|
274
|
}
|
317
|
275
|
|
318
|
276
|
|
src/ftinspect/models/ttsettingscomboboxmodel.hpp
→
src/ftinspect/models/customcomboboxmodels.hpp
... |
... |
@@ -71,25 +71,47 @@ public: |
71
|
71
|
|
72
|
72
|
|
73
|
73
|
// A simple key-displayName-value model for QComboBox.
|
74
|
|
-class SimpleComboBoxModel
|
75
|
|
-: public QAbstractListModel
|
|
74
|
+template <class T>
|
|
75
|
+class SimpleComboBoxModelImpl
|
76
|
76
|
{
|
77
|
|
- Q_OBJECT
|
78
|
77
|
public:
|
79
|
78
|
struct ComboBoxItem
|
80
|
79
|
{
|
81
|
|
- int value;
|
|
80
|
+ T value;
|
82
|
81
|
QString displayName;
|
83
|
82
|
};
|
84
|
83
|
|
85
|
|
- explicit SimpleComboBoxModel(QObject* parent);
|
86
|
|
- ~SimpleComboBoxModel() override = default;
|
|
84
|
+ SimpleComboBoxModelImpl() {}
|
|
85
|
+ virtual ~SimpleComboBoxModelImpl() = default;
|
87
|
86
|
|
88
|
|
- int rowCount(const QModelIndex& parent) const;
|
89
|
|
- QVariant data(const QModelIndex& index,
|
90
|
|
- int role) const;
|
|
87
|
+ virtual int
|
|
88
|
+ rowCount(const QModelIndex& parent) const
|
|
89
|
+ {
|
|
90
|
+ return items_.size();
|
|
91
|
+ }
|
91
|
92
|
|
92
|
|
- int indexToValue(int index);
|
|
93
|
+
|
|
94
|
+ virtual QVariant
|
|
95
|
+ data(const QModelIndex& index,
|
|
96
|
+ int role) const
|
|
97
|
+ {
|
|
98
|
+ if (role != Qt::DisplayRole)
|
|
99
|
+ return QVariant{};
|
|
100
|
+
|
|
101
|
+ int r = index.row();
|
|
102
|
+ if (r < 0 || r >= items_.size())
|
|
103
|
+ return QVariant{};
|
|
104
|
+ return items_[r].displayName;
|
|
105
|
+ }
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+ virtual T
|
|
109
|
+ indexToValue(int index)
|
|
110
|
+ {
|
|
111
|
+ if (index < 0 || index >= items_.size())
|
|
112
|
+ return T();
|
|
113
|
+ return items_[index].value;
|
|
114
|
+ }
|
93
|
115
|
|
94
|
116
|
protected:
|
95
|
117
|
QHash<int, ComboBoxItem> items_;
|
... |
... |
@@ -97,7 +119,8 @@ protected: |
97
|
119
|
|
98
|
120
|
|
99
|
121
|
class LCDFilterComboBoxModel
|
100
|
|
-: public SimpleComboBoxModel
|
|
122
|
+: public QAbstractListModel,
|
|
123
|
+ public SimpleComboBoxModelImpl<int>
|
101
|
124
|
{
|
102
|
125
|
Q_OBJECT
|
103
|
126
|
public:
|
... |
... |
@@ -108,11 +131,26 @@ public: |
108
|
131
|
QString displayName;
|
109
|
132
|
};
|
110
|
133
|
|
|
134
|
+
|
111
|
135
|
explicit LCDFilterComboBoxModel(QObject* parent);
|
112
|
136
|
virtual ~LCDFilterComboBoxModel() = default;
|
113
|
137
|
|
|
138
|
+
|
|
139
|
+ int rowCount(const QModelIndex& parent) const override
|
|
140
|
+ {
|
|
141
|
+ return SimpleComboBoxModelImpl::rowCount(parent);
|
|
142
|
+ }
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+ QVariant
|
|
146
|
+ data(const QModelIndex& index,
|
|
147
|
+ int role) const override
|
|
148
|
+ {
|
|
149
|
+ return SimpleComboBoxModelImpl::data(index, role);
|
|
150
|
+ }
|
|
151
|
+
|
114
|
152
|
public:
|
115
|
|
- enum LCDFilter
|
|
153
|
+ enum LCDFilter : int
|
116
|
154
|
{
|
117
|
155
|
LCDFilter_Default,
|
118
|
156
|
LCDFilter_Light,
|
... |
... |
@@ -122,8 +160,18 @@ public: |
122
|
160
|
};
|
123
|
161
|
|
124
|
162
|
|
|
163
|
+struct AASetting
|
|
164
|
+{
|
|
165
|
+ // No default value for braced init - No C++14, what a pain!
|
|
166
|
+ int loadFlag;
|
|
167
|
+ int renderMode;
|
|
168
|
+ bool isBGR;
|
|
169
|
+};
|
|
170
|
+
|
|
171
|
+
|
125
|
172
|
class AntiAliasingComboBoxModel
|
126
|
|
-: public SimpleComboBoxModel
|
|
173
|
+: public QAbstractListModel,
|
|
174
|
+ public SimpleComboBoxModelImpl<AASetting>
|
127
|
175
|
{
|
128
|
176
|
Q_OBJECT
|
129
|
177
|
public:
|
... |
... |
@@ -136,6 +184,13 @@ public: |
136
|
184
|
int role) const;
|
137
|
185
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
138
|
186
|
|
|
187
|
+
|
|
188
|
+ int rowCount(const QModelIndex& parent) const override
|
|
189
|
+ {
|
|
190
|
+ return SimpleComboBoxModelImpl::rowCount(parent);
|
|
191
|
+ }
|
|
192
|
+
|
|
193
|
+
|
139
|
194
|
void setLightAntiAliasingEnabled(bool enabled)
|
140
|
195
|
{
|
141
|
196
|
lightAntiAliasingEnabled_ = enabled;
|
src/ftinspect/panels/continuous.cpp
... |
... |
@@ -130,6 +130,11 @@ ContinuousTab::updateFromCurrentSubTab() |
130
|
130
|
canvas_->setBeginIndex(allGlyphsTab_->glyphBeginindex());
|
131
|
131
|
canvas_->setLimitIndex(allGlyphsTab_->glyphLimitIndex());
|
132
|
132
|
canvas_->setCharMapIndex(allGlyphsTab_->charMapIndex());
|
|
133
|
+
|
|
134
|
+ canvas_->setFancyParams(allGlyphsTab_->xEmboldening(),
|
|
135
|
+ allGlyphsTab_->yEmboldening(),
|
|
136
|
+ allGlyphsTab_->slanting());
|
|
137
|
+ canvas_->setStrokeRadius(allGlyphsTab_->strokeRadius());
|
133
|
138
|
break;
|
134
|
139
|
}
|
135
|
140
|
}
|
... |
... |
@@ -140,9 +145,11 @@ ContinousAllGlyphsTab::ContinousAllGlyphsTab(QWidget* parent) |
140
|
145
|
{
|
141
|
146
|
createLayout();
|
142
|
147
|
|
143
|
|
- QVector<CharMapInfo> tempCharMaps;
|
|
148
|
+ std::vector<CharMapInfo> tempCharMaps;
|
144
|
149
|
setCharMaps(tempCharMaps); // pass in an empty one
|
145
|
150
|
|
|
151
|
+ checkSubMode();
|
|
152
|
+ setDefaults();
|
146
|
153
|
createConnections();
|
147
|
154
|
}
|
148
|
155
|
|
... |
... |
@@ -169,13 +176,41 @@ ContinousAllGlyphsTab::subMode() |
169
|
176
|
}
|
170
|
177
|
|
171
|
178
|
|
|
179
|
+double
|
|
180
|
+ContinousAllGlyphsTab::xEmboldening()
|
|
181
|
+{
|
|
182
|
+ return xEmboldeningSpinBox_->value();
|
|
183
|
+}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+double
|
|
187
|
+ContinousAllGlyphsTab::yEmboldening()
|
|
188
|
+{
|
|
189
|
+ return yEmboldeningSpinBox_->value();
|
|
190
|
+}
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+double
|
|
194
|
+ContinousAllGlyphsTab::slanting()
|
|
195
|
+{
|
|
196
|
+ return slantSpinBox_->value();
|
|
197
|
+}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+double
|
|
201
|
+ContinousAllGlyphsTab::strokeRadius()
|
|
202
|
+{
|
|
203
|
+ return strokeRadiusSpinBox_->value();
|
|
204
|
+}
|
|
205
|
+
|
|
206
|
+
|
172
|
207
|
int
|
173
|
208
|
ContinousAllGlyphsTab::charMapIndex()
|
174
|
209
|
{
|
175
|
210
|
auto index = charMapSelector_->currentIndex() - 1;
|
176
|
211
|
if (index <= -1)
|
177
|
212
|
return -1;
|
178
|
|
- if (index >= charMaps_.size())
|
|
213
|
+ if (static_cast<unsigned>(index) >= charMaps_.size())
|
179
|
214
|
return -1;
|
180
|
215
|
return index;
|
181
|
216
|
}
|
... |
... |
@@ -205,7 +240,7 @@ ContinousAllGlyphsTab::setDisplayingCount(int count) |
205
|
240
|
|
206
|
241
|
#define EncodingRole (Qt::UserRole + 10)
|
207
|
242
|
void
|
208
|
|
-ContinousAllGlyphsTab::setCharMaps(QVector<CharMapInfo>& charMaps)
|
|
243
|
+ContinousAllGlyphsTab::setCharMaps(std::vector<CharMapInfo>& charMaps)
|
209
|
244
|
{
|
210
|
245
|
charMaps_ = charMaps;
|
211
|
246
|
int oldIndex = charMapSelector_->currentIndex();
|
... |
... |
@@ -263,6 +298,20 @@ ContinousAllGlyphsTab::updateLimitIndex() |
263
|
298
|
}
|
264
|
299
|
|
265
|
300
|
|
|
301
|
+void
|
|
302
|
+ContinousAllGlyphsTab::checkSubMode()
|
|
303
|
+{
|
|
304
|
+ auto isFancy = subMode() == GlyphContinuous::AG_Fancy;
|
|
305
|
+ auto isStroked = subMode() == GlyphContinuous::AG_Stroked;
|
|
306
|
+ xEmboldeningSpinBox_->setEnabled(isFancy);
|
|
307
|
+ yEmboldeningSpinBox_->setEnabled(isFancy);
|
|
308
|
+ slantSpinBox_->setEnabled(isFancy);
|
|
309
|
+ strokeRadiusSpinBox_->setEnabled(isStroked);
|
|
310
|
+
|
|
311
|
+ emit changed();
|
|
312
|
+}
|
|
313
|
+
|
|
314
|
+
|
266
|
315
|
void
|
267
|
316
|
ContinousAllGlyphsTab::createLayout()
|
268
|
317
|
{
|
... |
... |
@@ -276,13 +325,36 @@ ContinousAllGlyphsTab::createLayout() |
276
|
325
|
|
277
|
326
|
// Note: in sync with the enum!!
|
278
|
327
|
modeSelector_->insertItem(GlyphContinuous::AG_AllGlyphs, tr("All Glyphs"));
|
279
|
|
- modeSelector_->insertItem(GlyphContinuous::AG_Fancy, tr("Fancy"));
|
|
328
|
+ modeSelector_->insertItem(GlyphContinuous::AG_Fancy,
|
|
329
|
+ tr("Fancy (Embolding & Slanting)"));
|
280
|
330
|
modeSelector_->insertItem(GlyphContinuous::AG_Stroked, tr("Stroked"));
|
281
|
331
|
modeSelector_->insertItem(GlyphContinuous::AG_Waterfall, tr("Waterfall"));
|
282
|
332
|
modeSelector_->setCurrentIndex(GlyphContinuous::AG_AllGlyphs);
|
283
|
333
|
|
284
|
334
|
modeLabel_ = new QLabel(tr("Mode:"), this);
|
285
|
335
|
charMapLabel_ = new QLabel(tr("Char Map:"), this);
|
|
336
|
+ xEmboldeningLabel_ = new QLabel(tr("Hori. Embolding:"), this);
|
|
337
|
+ yEmboldeningLabel_ = new QLabel(tr("Vert. Embolding:"), this);
|
|
338
|
+ slantLabel_ = new QLabel(tr("Slanting:"), this);
|
|
339
|
+ strokeRadiusLabel_ = new QLabel(tr("Stroke Radius:"), this);
|
|
340
|
+
|
|
341
|
+ xEmboldeningSpinBox_ = new QDoubleSpinBox(this);
|
|
342
|
+ yEmboldeningSpinBox_ = new QDoubleSpinBox(this);
|
|
343
|
+ slantSpinBox_ = new QDoubleSpinBox(this);
|
|
344
|
+ strokeRadiusSpinBox_ = new QDoubleSpinBox(this);
|
|
345
|
+
|
|
346
|
+ xEmboldeningSpinBox_->setSingleStep(0.005);
|
|
347
|
+ xEmboldeningSpinBox_->setMinimum(-0.1);
|
|
348
|
+ xEmboldeningSpinBox_->setMaximum(0.1);
|
|
349
|
+ yEmboldeningSpinBox_->setSingleStep(0.005);
|
|
350
|
+ yEmboldeningSpinBox_->setMinimum(-0.1);
|
|
351
|
+ yEmboldeningSpinBox_->setMaximum(0.1);
|
|
352
|
+ slantSpinBox_->setSingleStep(0.02);
|
|
353
|
+ slantSpinBox_->setMinimum(-1);
|
|
354
|
+ slantSpinBox_->setMaximum(1);
|
|
355
|
+ strokeRadiusSpinBox_->setSingleStep(0.005);
|
|
356
|
+ strokeRadiusSpinBox_->setMinimum(0);
|
|
357
|
+ strokeRadiusSpinBox_->setMaximum(0.05);
|
286
|
358
|
|
287
|
359
|
layout_ = new QGridLayout;
|
288
|
360
|
layout_->addWidget(indexSelector_, 0, 0, 1, 2);
|
... |
... |
@@ -291,7 +363,17 @@ ContinousAllGlyphsTab::createLayout() |
291
|
363
|
layout_->addWidget(modeSelector_, 1, 1);
|
292
|
364
|
layout_->addWidget(charMapSelector_, 2, 1);
|
293
|
365
|
|
|
366
|
+ layout_->addWidget(xEmboldeningLabel_, 1, 2);
|
|
367
|
+ layout_->addWidget(yEmboldeningLabel_, 2, 2);
|
|
368
|
+ layout_->addWidget(slantLabel_, 3, 2);
|
|
369
|
+ layout_->addWidget(strokeRadiusLabel_, 3, 0);
|
|
370
|
+ layout_->addWidget(xEmboldeningSpinBox_, 1, 3);
|
|
371
|
+ layout_->addWidget(yEmboldeningSpinBox_, 2, 3);
|
|
372
|
+ layout_->addWidget(slantSpinBox_, 3, 3);
|
|
373
|
+ layout_->addWidget(strokeRadiusSpinBox_, 3, 1);
|
|
374
|
+
|
294
|
375
|
layout_->setColumnStretch(1, 1);
|
|
376
|
+ layout_->setColumnStretch(3, 1);
|
295
|
377
|
|
296
|
378
|
setLayout(layout_);
|
297
|
379
|
}
|
... |
... |
@@ -302,9 +384,22 @@ ContinousAllGlyphsTab::createConnections() |
302
|
384
|
connect(indexSelector_, &GlyphIndexSelector::currentIndexChanged,
|
303
|
385
|
this, &ContinousAllGlyphsTab::changed);
|
304
|
386
|
connect(modeSelector_, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
305
|
|
- this, &ContinousAllGlyphsTab::changed);
|
|
387
|
+ this, &ContinousAllGlyphsTab::checkSubMode);
|
306
|
388
|
connect(charMapSelector_, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
307
|
389
|
this, &ContinousAllGlyphsTab::charMapChanged);
|
|
390
|
+
|
|
391
|
+ connect(xEmboldeningSpinBox_,
|
|
392
|
+ QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
|
393
|
+ this, &ContinousAllGlyphsTab::changed);
|
|
394
|
+ connect(yEmboldeningSpinBox_,
|
|
395
|
+ QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
|
396
|
+ this, &ContinousAllGlyphsTab::changed);
|
|
397
|
+ connect(slantSpinBox_,
|
|
398
|
+ QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
|
399
|
+ this, &ContinousAllGlyphsTab::changed);
|
|
400
|
+ connect(strokeRadiusSpinBox_,
|
|
401
|
+ QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
|
402
|
+ this, &ContinousAllGlyphsTab::changed);
|
308
|
403
|
}
|
309
|
404
|
|
310
|
405
|
|
... |
... |
@@ -324,7 +419,8 @@ ContinousAllGlyphsTab::charMapChanged() |
324
|
419
|
int newIndex = charMapSelector_->currentIndex();
|
325
|
420
|
if (newIndex != lastCharMapIndex_)
|
326
|
421
|
{
|
327
|
|
- if (newIndex <= 0 || charMaps_.size() <= newIndex - 1)
|
|
422
|
+ if (newIndex <= 0
|
|
423
|
+ || charMaps_.size() <= static_cast<unsigned>(newIndex - 1))
|
328
|
424
|
setGlyphBeginindex(0);
|
329
|
425
|
else if (charMaps_[newIndex - 1].maxIndex <= 20)
|
330
|
426
|
setGlyphBeginindex(charMaps_[newIndex - 1].maxIndex - 1);
|
... |
... |
@@ -339,4 +435,14 @@ ContinousAllGlyphsTab::charMapChanged() |
339
|
435
|
}
|
340
|
436
|
|
341
|
437
|
|
|
438
|
+void
|
|
439
|
+ContinousAllGlyphsTab::setDefaults()
|
|
440
|
+{
|
|
441
|
+ xEmboldeningSpinBox_->setValue(0.04);
|
|
442
|
+ yEmboldeningSpinBox_->setValue(0.04);
|
|
443
|
+ slantSpinBox_->setValue(0.22);
|
|
444
|
+ strokeRadiusSpinBox_->setValue(0.02);
|
|
445
|
+}
|
|
446
|
+
|
|
447
|
+
|
342
|
448
|
// end of continuous.cpp |
src/ftinspect/panels/continuous.hpp
... |
... |
@@ -12,10 +12,10 @@ |
12
|
12
|
#include "../rendering/glyphcontinuous.hpp"
|
13
|
13
|
#include "../engine/engine.hpp"
|
14
|
14
|
|
|
15
|
+#include <vector>
|
15
|
16
|
#include <QWidget>
|
16
|
17
|
#include <QLabel>
|
17
|
18
|
#include <QComboBox>
|
18
|
|
-#include <QVector>
|
19
|
19
|
#include <QGridLayout>
|
20
|
20
|
#include <QBoxLayout>
|
21
|
21
|
|
... |
... |
@@ -79,6 +79,10 @@ public: |
79
|
79
|
int glyphBeginindex();
|
80
|
80
|
int glyphLimitIndex();
|
81
|
81
|
GlyphContinuous::SubModeAllGlyphs subMode();
|
|
82
|
+ double xEmboldening();
|
|
83
|
+ double yEmboldening();
|
|
84
|
+ double slanting();
|
|
85
|
+ double strokeRadius();
|
82
|
86
|
|
83
|
87
|
// -1: Glyph order, otherwise the char map index in the original list
|
84
|
88
|
int charMapIndex();
|
... |
... |
@@ -88,10 +92,12 @@ public: |
88
|
92
|
void setGlyphCount(int count);
|
89
|
93
|
void setDisplayingCount(int count);
|
90
|
94
|
|
91
|
|
- void setCharMaps(QVector<CharMapInfo>& charMaps);
|
|
95
|
+ void setCharMaps(std::vector<CharMapInfo>& charMaps);
|
92
|
96
|
// This doesn't trigger either.
|
93
|
97
|
void updateLimitIndex();
|
94
|
98
|
|
|
99
|
+ void checkSubMode();
|
|
100
|
+
|
95
|
101
|
signals:
|
96
|
102
|
void changed();
|
97
|
103
|
|
... |
... |
@@ -106,16 +112,27 @@ private: |
106
|
112
|
|
107
|
113
|
QLabel* modeLabel_;
|
108
|
114
|
QLabel* charMapLabel_;
|
|
115
|
+ QLabel* xEmboldeningLabel_;
|
|
116
|
+ QLabel* yEmboldeningLabel_;
|
|
117
|
+ QLabel* slantLabel_;
|
|
118
|
+ QLabel* strokeRadiusLabel_;
|
|
119
|
+
|
|
120
|
+ QDoubleSpinBox* xEmboldeningSpinBox_;
|
|
121
|
+ QDoubleSpinBox* yEmboldeningSpinBox_;
|
|
122
|
+ QDoubleSpinBox* slantSpinBox_;
|
|
123
|
+ QDoubleSpinBox* strokeRadiusSpinBox_;
|
109
|
124
|
|
110
|
125
|
QGridLayout* layout_;
|
111
|
126
|
|
112
|
|
- QVector<CharMapInfo> charMaps_;
|
|
127
|
+ std::vector<CharMapInfo> charMaps_;
|
113
|
128
|
|
114
|
129
|
void createLayout();
|
115
|
130
|
void createConnections();
|
116
|
131
|
|
117
|
132
|
QString formatIndex(int index);
|
118
|
133
|
void charMapChanged();
|
|
134
|
+
|
|
135
|
+ void setDefaults();
|
119
|
136
|
};
|
120
|
137
|
|
121
|
138
|
|
src/ftinspect/panels/settingpanel.cpp
... |
... |
@@ -172,8 +172,12 @@ SettingPanel::syncSettings() |
172
|
172
|
engine_->setLcdFilter(
|
173
|
173
|
static_cast<FT_LcdFilter>(lcdFilterComboboxModel_->indexToValue(
|
174
|
174
|
lcdFilterComboBox_->currentIndex())));
|
175
|
|
- engine_->setAntiAliasingTarget(antiAliasingComboBoxModel_->indexToValue(
|
176
|
|
- antiAliasingComboBox_->currentIndex()));
|
|
175
|
+
|
|
176
|
+ auto aaSettings = antiAliasingComboBoxModel_->indexToValue(
|
|
177
|
+ antiAliasingComboBox_->currentIndex());
|
|
178
|
+ engine_->setAntiAliasingTarget(aaSettings.loadFlag);
|
|
179
|
+ engine_->setRenderMode(aaSettings.renderMode);
|
|
180
|
+
|
177
|
181
|
engine_->setAntiAliasingEnabled(antiAliasingComboBox_->currentIndex()
|
178
|
182
|
!= AntiAliasingComboBoxModel::AntiAliasing_None);
|
179
|
183
|
engine_->setHinting(hintingCheckBox_->isChecked());
|
... |
... |
@@ -184,6 +188,9 @@ SettingPanel::syncSettings() |
184
|
188
|
engine_->setShowSegments(segmentDrawingCheckBox_->isChecked());
|
185
|
189
|
|
186
|
190
|
engine_->setGamma(gammaSlider_->value());
|
|
191
|
+
|
|
192
|
+ engine_->setEmbeddedBitmap(embeddedBitmapCheckBox_->isChecked());
|
|
193
|
+ engine_->setLCDUsesBGR(aaSettings.isBGR);
|
187
|
194
|
}
|
188
|
195
|
|
189
|
196
|
|
... |
... |
@@ -218,6 +225,8 @@ SettingPanel::createConnections() |
218
|
225
|
|
219
|
226
|
connect(autoHintingCheckBox_, &QCheckBox::clicked,
|
220
|
227
|
this, &SettingPanel::checkAutoHinting);
|
|
228
|
+ connect(embeddedBitmapCheckBox_, &QCheckBox::clicked,
|
|
229
|
+ this, &SettingPanel::repaintNeeded);
|
221
|
230
|
}
|
222
|
231
|
|
223
|
232
|
|
... |
... |
@@ -239,6 +248,7 @@ SettingPanel::createLayout() |
239
|
248
|
verticalHintingCheckBox_ = new QCheckBox(tr("Vertical Hinting"), this);
|
240
|
249
|
blueZoneHintingCheckBox_ = new QCheckBox(tr("Blue-Zone Hinting"), this);
|
241
|
250
|
segmentDrawingCheckBox_ = new QCheckBox(tr("Segment Drawing"), this);
|
|
251
|
+ embeddedBitmapCheckBox_ = new QCheckBox(tr("Enable Embedded Bitmap"), this);
|
242
|
252
|
|
243
|
253
|
antiAliasingLabel_ = new QLabel(tr("Anti-Aliasing"), this);
|
244
|
254
|
antiAliasingLabel_->setAlignment(Qt::AlignRight);
|
... |
... |
@@ -329,6 +339,7 @@ SettingPanel::createLayout() |
329
|
339
|
generalTabLayout_->addSpacing(20); // XXX px
|
330
|
340
|
generalTabLayout_->addStretch(1);
|
331
|
341
|
generalTabLayout_->addLayout(gammaLayout_);
|
|
342
|
+ generalTabLayout_->addWidget(embeddedBitmapCheckBox_);
|
332
|
343
|
generalTabLayout_->addSpacing(20); // XXX px
|
333
|
344
|
generalTabLayout_->addStretch(1);
|
334
|
345
|
|
... |
... |
@@ -376,6 +387,7 @@ SettingPanel::setDefaults() |
376
|
387
|
horizontalHintingCheckBox_->setChecked(true);
|
377
|
388
|
verticalHintingCheckBox_->setChecked(true);
|
378
|
389
|
blueZoneHintingCheckBox_->setChecked(true);
|
|
390
|
+ embeddedBitmapCheckBox_->setChecked(false);
|
379
|
391
|
|
380
|
392
|
gammaSlider_->setValue(18); // 1.8
|
381
|
393
|
}
|
src/ftinspect/panels/settingpanel.hpp
... |
... |
@@ -63,6 +63,7 @@ private: |
63
|
63
|
QCheckBox* blueZoneHintingCheckBox_;
|
64
|
64
|
QCheckBox* segmentDrawingCheckBox_;
|
65
|
65
|
QCheckBox* autoHintingCheckBox_;
|
|
66
|
+ QCheckBox* embeddedBitmapCheckBox_;
|
66
|
67
|
|
67
|
68
|
AntiAliasingComboBoxModel* antiAliasingComboBoxModel_;
|
68
|
69
|
HintingModeComboBoxModel* hintingModeComboBoxModel_;
|
src/ftinspect/panels/singular.cpp
... |
... |
@@ -87,29 +87,21 @@ SingularTab::drawGlyph() |
87
|
87
|
}
|
88
|
88
|
|
89
|
89
|
syncSettings();
|
90
|
|
- FT_Outline* outline = engine_->loadOutline(currentGlyphIndex_);
|
91
|
|
- if (outline)
|
|
90
|
+ FT_Glyph glyph = engine_->loadGlyph(currentGlyphIndex_);
|
|
91
|
+ if (glyph)
|
92
|
92
|
{
|
93
|
93
|
if (showBitmapCheckBox_->isChecked())
|
94
|
94
|
{
|
95
|
|
- // XXX support LCD
|
96
|
|
- FT_Pixel_Mode pixelMode = FT_PIXEL_MODE_GRAY;
|
97
|
|
- if (!engine_->antiAliasingEnabled())
|
98
|
|
- pixelMode = FT_PIXEL_MODE_MONO;
|
99
|
|
-
|
100
|
95
|
currentGlyphBitmapItem_
|
101
|
|
- = new GlyphBitmap(outline,
|
102
|
|
- engine_->ftLibrary(),
|
103
|
|
- pixelMode,
|
104
|
|
- graphicsDefault_->monoColorTable,
|
105
|
|
- graphicsDefault_->grayColorTable);
|
|
96
|
+ = new GlyphBitmap(glyph,
|
|
97
|
+ engine_);
|
106
|
98
|
glyphScene_->addItem(currentGlyphBitmapItem_);
|
107
|
99
|
}
|
108
|
100
|
|
109
|
101
|
if (showOutlinesCheckBox_->isChecked())
|
110
|
102
|
{
|
111
|
103
|
currentGlyphOutlineItem_ = new GlyphOutline(graphicsDefault_->outlinePen,
|
112
|
|
- outline);
|
|
104
|
+ glyph);
|
113
|
105
|
glyphScene_->addItem(currentGlyphOutlineItem_);
|
114
|
106
|
}
|
115
|
107
|
|
... |
... |
@@ -117,7 +109,7 @@ SingularTab::drawGlyph() |
117
|
109
|
{
|
118
|
110
|
currentGlyphPointsItem_ = new GlyphPoints(graphicsDefault_->onPen,
|
119
|
111
|
graphicsDefault_->offPen,
|
120
|
|
- outline);
|
|
112
|
+ glyph);
|
121
|
113
|
glyphScene_->addItem(currentGlyphPointsItem_);
|
122
|
114
|
|
123
|
115
|
if (showPointNumbersCheckBox_->isChecked())
|
... |
... |
@@ -125,7 +117,7 @@ SingularTab::drawGlyph() |
125
|
117
|
currentGlyphPointNumbersItem_
|
126
|
118
|
= new GlyphPointNumbers(graphicsDefault_->onPen,
|
127
|
119
|
graphicsDefault_->offPen,
|
128
|
|
- outline);
|
|
120
|
+ glyph);
|
129
|
121
|
glyphScene_->addItem(currentGlyphPointNumbersItem_);
|
130
|
122
|
}
|
131
|
123
|
}
|
src/ftinspect/rendering/glyphbitmap.cpp
... |
... |
@@ -6,33 +6,26 @@ |
6
|
6
|
#include "glyphbitmap.hpp"
|
7
|
7
|
|
8
|
8
|
#include "renderutils.hpp"
|
|
9
|
+#include "../engine/engine.hpp"
|
9
|
10
|
|
10
|
11
|
#include <cmath>
|
11
|
12
|
#include <QPainter>
|
12
|
13
|
#include <QStyleOptionGraphicsItem>
|
|
14
|
+#include <freetype/ftbitmap.h>
|
13
|
15
|
|
14
|
16
|
|
15
|
|
-GlyphBitmap::GlyphBitmap(FT_Outline* outline,
|
16
|
|
- FT_Library lib,
|
17
|
|
- FT_Pixel_Mode pxlMode,
|
18
|
|
- const QVector<QRgb>& monoColorTbl,
|
19
|
|
- const QVector<QRgb>& grayColorTbl)
|
20
|
|
-: library_(lib),
|
21
|
|
- pixelMode_(pxlMode),
|
22
|
|
- monoColorTable_(monoColorTbl),
|
23
|
|
- grayColorTable_(grayColorTbl)
|
|
17
|
+GlyphBitmap::GlyphBitmap(FT_Glyph glyph,
|
|
18
|
+ Engine* engine)
|
24
|
19
|
{
|
25
|
|
- // make a copy of the outline since we are going to manipulate it
|
26
|
|
- FT_BBox cbox;
|
27
|
|
- transformed_ = transformOutlineToOrigin(lib, outline, &cbox);
|
28
|
|
- boundingRect_.setCoords(cbox.xMin / 64, -cbox.yMax / 64,
|
29
|
|
- cbox.xMax / 64, -cbox.yMin / 64);
|
|
20
|
+ QRect bRect;
|
|
21
|
+ image_ = engine->convertBitmapToQImage(glyph, &bRect);
|
|
22
|
+ boundingRect_ = bRect; // QRectF to QRect
|
30
|
23
|
}
|
31
|
24
|
|
32
|
25
|
|
33
|
26
|
GlyphBitmap::~GlyphBitmap()
|
34
|
27
|
{
|
35
|
|
- FT_Outline_Done(library_, &transformed_);
|
|
28
|
+ delete image_;
|
36
|
29
|
}
|
37
|
30
|
|
38
|
31
|
QRectF
|
... |
... |
@@ -47,40 +40,9 @@ GlyphBitmap::paint(QPainter* painter, |
47
|
40
|
const QStyleOptionGraphicsItem* option,
|
48
|
41
|
QWidget*)
|
49
|
42
|
{
|
50
|
|
- FT_Bitmap bitmap;
|
51
|
|
-
|
52
|
|
- int height = static_cast<int>(ceil(boundingRect_.height()));
|
53
|
|
- int width = static_cast<int>(ceil(boundingRect_.width()));
|
54
|
|
- QImage::Format format = QImage::Format_Indexed8;
|
55
|
|
-
|
56
|
|
- // XXX cover LCD and color
|
57
|
|
- if (pixelMode_ == FT_PIXEL_MODE_MONO)
|
58
|
|
- format = QImage::Format_Mono;
|
59
|
|
-
|
60
|
|
- QImage image(QSize(width, height), format);
|
61
|
|
-
|
62
|
|
- if (pixelMode_ == FT_PIXEL_MODE_MONO)
|
63
|
|
- image.setColorTable(monoColorTable_);
|
64
|
|
- else
|
65
|
|
- image.setColorTable(grayColorTable_);
|
66
|
|
-
|
67
|
|
- image.fill(0);
|
68
|
|
-
|
69
|
|
- bitmap.rows = static_cast<unsigned int>(height);
|
70
|
|
- bitmap.width = static_cast<unsigned int>(width);
|
71
|
|
- bitmap.buffer = image.bits();
|
72
|
|
- bitmap.pitch = image.bytesPerLine();
|
73
|
|
- bitmap.pixel_mode = pixelMode_;
|
74
|
|
-
|
75
|
|
- FT_Error error = FT_Outline_Get_Bitmap(library_,
|
76
|
|
- &transformed_,
|
77
|
|
- &bitmap);
|
78
|
|
- if (error)
|
79
|
|
- {
|
80
|
|
- // XXX error handling
|
|
43
|
+ if (!image_)
|
81
|
44
|
return;
|
82
|
|
- }
|
83
|
|
-
|
|
45
|
+
|
84
|
46
|
// `drawImage' doesn't work as expected:
|
85
|
47
|
// the larger the zoom, the more the pixel rectangle positions
|
86
|
48
|
// deviate from the grid lines
|
... |
... |
@@ -94,11 +56,11 @@ GlyphBitmap::paint(QPainter* painter, |
94
|
56
|
|
95
|
57
|
painter->setPen(Qt::NoPen);
|
96
|
58
|
|
97
|
|
- for (int x = 0; x < image.width(); x++)
|
98
|
|
- for (int y = 0; y < image.height(); y++)
|
|
59
|
+ for (int x = 0; x < image_->width(); x++)
|
|
60
|
+ for (int y = 0; y < image_->height(); y++)
|
99
|
61
|
{
|
100
|
62
|
// be careful not to lose the alpha channel
|
101
|
|
- QRgb p = image.pixel(x, y);
|
|
63
|
+ QRgb p = image_->pixel(x, y);
|
102
|
64
|
painter->fillRect(QRectF(x + boundingRect_.left() - 1 / lod / 2,
|
103
|
65
|
y + boundingRect_.top() - 1 / lod / 2,
|
104
|
66
|
1 + 1 / lod,
|
... |
... |
@@ -108,7 +70,9 @@ GlyphBitmap::paint(QPainter* painter, |
108
|
70
|
qBlue(p),
|
109
|
71
|
qAlpha(p)));
|
110
|
72
|
}
|
|
73
|
+
|
111
|
74
|
#endif
|
|
75
|
+
|
112
|
76
|
}
|
113
|
77
|
|
114
|
78
|
|
src/ftinspect/rendering/glyphbitmap.hpp
... |
... |
@@ -10,18 +10,18 @@ |
10
|
10
|
|
11
|
11
|
#include <ft2build.h>
|
12
|
12
|
#include <freetype/freetype.h>
|
|
13
|
+#include <freetype/ftglyph.h>
|
13
|
14
|
#include <freetype/ftoutln.h>
|
14
|
15
|
|
15
|
16
|
|
|
17
|
+class Engine;
|
|
18
|
+
|
16
|
19
|
class GlyphBitmap
|
17
|
20
|
: public QGraphicsItem
|
18
|
21
|
{
|
19
|
22
|
public:
|
20
|
|
- GlyphBitmap(FT_Outline* outline,
|
21
|
|
- FT_Library library,
|
22
|
|
- FT_Pixel_Mode pixelMode,
|
23
|
|
- const QVector<QRgb>& monoColorTable,
|
24
|
|
- const QVector<QRgb>& grayColorTable);
|
|
23
|
+ GlyphBitmap(FT_Glyph glyph,
|
|
24
|
+ Engine* engine);
|
25
|
25
|
~GlyphBitmap() override;
|
26
|
26
|
QRectF boundingRect() const override;
|
27
|
27
|
void paint(QPainter* painter,
|
... |
... |
@@ -29,11 +29,7 @@ public: |
29
|
29
|
QWidget* widget) override;
|
30
|
30
|
|
31
|
31
|
private:
|
32
|
|
- FT_Outline transformed_;
|
33
|
|
- FT_Library library_;
|
34
|
|
- unsigned char pixelMode_;
|
35
|
|
- const QVector<QRgb>& monoColorTable_;
|
36
|
|
- const QVector<QRgb>& grayColorTable_;
|
|
32
|
+ QImage* image_ = NULL;
|
37
|
33
|
QRectF boundingRect_;
|
38
|
34
|
};
|
39
|
35
|
|
src/ftinspect/rendering/glyphcontinuous.cpp
... |
... |
@@ -4,13 +4,13 @@ |
4
|
4
|
|
5
|
5
|
#include "glyphcontinuous.hpp"
|
6
|
6
|
|
|
7
|
+#include "../engine/engine.hpp"
|
|
8
|
+#include "../rendering/renderutils.hpp"
|
|
9
|
+
|
7
|
10
|
#include <cmath>
|
8
|
11
|
#include <QPainter>
|
9
|
12
|
#include <QWheelEvent>
|
10
|
13
|
|
11
|
|
-#include "../engine/engine.hpp"
|
12
|
|
-#include "../rendering/renderutils.hpp"
|
13
|
|
-
|
14
|
14
|
|
15
|
15
|
GlyphContinuous::GlyphContinuous(QWidget* parent, Engine* engine)
|
16
|
16
|
: QWidget(parent), engine_(engine)
|
... |
... |
@@ -18,6 +18,15 @@ GlyphContinuous::GlyphContinuous(QWidget* parent, Engine* engine) |
18
|
18
|
setAcceptDrops(false);
|
19
|
19
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
20
|
20
|
graphicsDefault_ = GraphicsDefault::deafultInstance();
|
|
21
|
+
|
|
22
|
+ FT_Stroker_New(engine_->ftLibrary(), &stroker_);
|
|
23
|
+}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+GlyphContinuous::~GlyphContinuous()
|
|
27
|
+{
|
|
28
|
+ cleanCloned();
|
|
29
|
+ FT_Stroker_Done(stroker_);
|
21
|
30
|
}
|
22
|
31
|
|
23
|
32
|
|
... |
... |
@@ -38,12 +47,9 @@ GlyphContinuous::paintEvent(QPaintEvent* event) |
38
|
47
|
switch (modeAG_)
|
39
|
48
|
{
|
40
|
49
|
case AG_AllGlyphs:
|
41
|
|
- paintAGAllGlyphs(&painter);
|
42
|
|
- break;
|
43
|
|
- // TODO more modes
|
44
|
50
|
case AG_Fancy:
|
45
|
|
- break;
|
46
|
51
|
case AG_Stroked:
|
|
52
|
+ paintAG(&painter);
|
47
|
53
|
break;
|
48
|
54
|
case AG_Waterfall:
|
49
|
55
|
break;
|
... |
... |
@@ -71,19 +77,114 @@ GlyphContinuous::wheelEvent(QWheelEvent* event) |
71
|
77
|
|
72
|
78
|
|
73
|
79
|
void
|
74
|
|
-GlyphContinuous::paintAGAllGlyphs(QPainter* painter)
|
|
80
|
+GlyphContinuous::paintAG(QPainter* painter)
|
75
|
81
|
{
|
|
82
|
+ if (modeAG_ == AG_Stroked)
|
|
83
|
+ {
|
|
84
|
+ auto radius = static_cast<FT_Fixed>(metrics_.y_ppem * 64 * strokeRadius_);
|
|
85
|
+ FT_Stroker_Set(stroker_, radius,
|
|
86
|
+ FT_STROKER_LINECAP_ROUND,
|
|
87
|
+ FT_STROKER_LINEJOIN_ROUND,
|
|
88
|
+ 0);
|
|
89
|
+ }
|
|
90
|
+
|
76
|
91
|
for (int i = beginIndex_; i < limitIndex_; i++)
|
77
|
92
|
{
|
78
|
93
|
unsigned index = i;
|
79
|
94
|
if (charMapIndex_ >= 0)
|
80
|
95
|
index = engine_->glyphIndexFromCharCode(i, charMapIndex_);
|
81
|
96
|
|
82
|
|
- if (!paintChar(painter, index))
|
|
97
|
+ if (!loadGlyph(index))
|
|
98
|
+ break;
|
|
99
|
+
|
|
100
|
+ // All Glyphs need no tranformation, and Waterfall isn't handled here.
|
|
101
|
+ switch (modeAG_)
|
|
102
|
+ {
|
|
103
|
+ case AG_Fancy:
|
|
104
|
+ transformGlyphAGFancy();
|
|
105
|
+ break;
|
|
106
|
+ case AG_Stroked:
|
|
107
|
+ transformGlyphAGStroked();
|
83
|
108
|
break;
|
|
109
|
+ default:;
|
|
110
|
+ }
|
|
111
|
+
|
|
112
|
+ if (!paintChar(painter))
|
|
113
|
+ break;
|
|
114
|
+ cleanCloned();
|
84
|
115
|
|
85
|
116
|
displayingCount_++;
|
86
|
117
|
}
|
|
118
|
+ cleanCloned();
|
|
119
|
+}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+void
|
|
123
|
+GlyphContinuous::transformGlyphAGFancy()
|
|
124
|
+{
|
|
125
|
+ // adopted from ftview.c:289
|
|
126
|
+ /***************************************************************/
|
|
127
|
+ /* */
|
|
128
|
+ /* 2*2 affine transformation matrix, 16.16 fixed float format */
|
|
129
|
+ /* */
|
|
130
|
+ /* Shear matrix: */
|
|
131
|
+ /* */
|
|
132
|
+ /* | x' | | 1 k | | x | x' = x + ky */
|
|
133
|
+ /* | | = | | * | | <==> */
|
|
134
|
+ /* | y' | | 0 1 | | y | y' = y */
|
|
135
|
+ /* */
|
|
136
|
+ /* outline' shear outline */
|
|
137
|
+ /* */
|
|
138
|
+ /***************************************************************/
|
|
139
|
+
|
|
140
|
+ FT_Matrix shear;
|
|
141
|
+ FT_Pos xstr, ystr;
|
|
142
|
+
|
|
143
|
+ shear.xx = 1 << 16;
|
|
144
|
+ shear.xy = static_cast<FT_Fixed>(slant_ * (1 << 16));
|
|
145
|
+ shear.yx = 0;
|
|
146
|
+ shear.yy = 1 << 16;
|
|
147
|
+
|
|
148
|
+ xstr = (FT_Pos)(metrics_.y_ppem * 64 * boldX_);
|
|
149
|
+ ystr = (FT_Pos)(metrics_.y_ppem * 64 * boldY_);
|
|
150
|
+
|
|
151
|
+ if (!isGlyphCloned_)
|
|
152
|
+ cloneGlyph();
|
|
153
|
+
|
|
154
|
+ if (glyph_->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
155
|
+ return; // TODO suuport non-outline: code below all depend on `outline_`!
|
|
156
|
+
|
|
157
|
+ FT_Outline_Transform(&outline_, &shear);
|
|
158
|
+ FT_Outline_EmboldenXY(&outline_, xstr, ystr);
|
|
159
|
+
|
|
160
|
+ if (glyph_->advance.x)
|
|
161
|
+ glyph_->advance.x += xstr;
|
|
162
|
+
|
|
163
|
+ if (glyph_->advance.y)
|
|
164
|
+ glyph_->advance.y += ystr;
|
|
165
|
+
|
|
166
|
+ //glyph_->metrics.width += xstr;
|
|
167
|
+ //glyph_->metrics.height += ystr;
|
|
168
|
+ //glyph_->metrics.horiAdvance += xstr;
|
|
169
|
+ //glyph_->metrics.vertAdvance += ystr;
|
|
170
|
+}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+void
|
|
174
|
+GlyphContinuous::transformGlyphAGStroked()
|
|
175
|
+{
|
|
176
|
+ //if (!isGlyphCloned_)
|
|
177
|
+ //cloneGlyph();
|
|
178
|
+ // Well, now here only outline glyph is supported.
|
|
179
|
+ if (glyph_->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
180
|
+ return;
|
|
181
|
+ auto error = FT_Glyph_Stroke(&glyph_, stroker_, 0);
|
|
182
|
+ if (!error)
|
|
183
|
+ {
|
|
184
|
+ isGlyphCloned_ = true;
|
|
185
|
+ isOutlineCloned_ = false;
|
|
186
|
+ outline_ = reinterpret_cast<FT_OutlineGlyph>(glyph_)->outline;
|
|
187
|
+ }
|
87
|
188
|
}
|
88
|
189
|
|
89
|
190
|
|
... |
... |
@@ -101,16 +202,11 @@ GlyphContinuous::prePaint() |
101
|
202
|
|
102
|
203
|
|
103
|
204
|
bool
|
104
|
|
-GlyphContinuous::paintChar(QPainter* painter,
|
105
|
|
- int index)
|
|
205
|
+GlyphContinuous::paintChar(QPainter* painter)
|
106
|
206
|
{
|
107
|
|
- auto glyph = engine_->loadGlyphWithoutUpdate(index);
|
108
|
|
- if (!glyph)
|
109
|
|
- return false;
|
110
|
|
-
|
111
|
207
|
// ftview.c:557
|
112
|
|
- int width = glyph->advance.x ? glyph->advance.x >> 16
|
113
|
|
- : metrics_.y_ppem / 2;
|
|
208
|
+ int width = glyph_->advance.x ? glyph_->advance.x >> 16
|
|
209
|
+ : metrics_.y_ppem / 2;
|
114
|
210
|
|
115
|
211
|
if (!checkFitX(x_ + width))
|
116
|
212
|
{
|
... |
... |
@@ -122,7 +218,7 @@ GlyphContinuous::paintChar(QPainter* painter, |
122
|
218
|
}
|
123
|
219
|
|
124
|
220
|
x_++; // extra space
|
125
|
|
- if (glyph->advance.x == 0)
|
|
221
|
+ if (glyph_->advance.x == 0)
|
126
|
222
|
{
|
127
|
223
|
// Draw a red square to indicate
|
128
|
224
|
painter->fillRect(x_, y_ - width, width, width,
|
... |
... |
@@ -136,15 +232,15 @@ GlyphContinuous::paintChar(QPainter* painter, |
136
|
232
|
|
137
|
233
|
// First translate the outline
|
138
|
234
|
|
139
|
|
- if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
235
|
+ if (glyph_->format != FT_GLYPH_FORMAT_OUTLINE)
|
140
|
236
|
return true; // XXX only outline is supported - need to impl others later
|
141
|
237
|
|
142
|
238
|
FT_BBox cbox;
|
143
|
239
|
// Don't forget to free this when returning
|
144
|
|
- auto outline = transformOutlineToOrigin(
|
145
|
|
- engine_->ftLibrary(),
|
146
|
|
- &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline,
|
147
|
|
- &cbox);
|
|
240
|
+ if (!isOutlineCloned_ && !isGlyphCloned_)
|
|
241
|
+ cloneOutline();
|
|
242
|
+
|
|
243
|
+ transformOutlineToOrigin(&outline_, &cbox);
|
148
|
244
|
|
149
|
245
|
auto outlineWidth = (cbox.xMax - cbox.xMin) / 64;
|
150
|
246
|
auto outlineHeight = (cbox.yMax - cbox.yMin) / 64;
|
... |
... |
@@ -175,12 +271,11 @@ GlyphContinuous::paintChar(QPainter* painter, |
175
|
271
|
bitmap.pixel_mode = aaEnabled ? FT_PIXEL_MODE_GRAY : FT_PIXEL_MODE_MONO;
|
176
|
272
|
|
177
|
273
|
FT_Error error = FT_Outline_Get_Bitmap(engine_->ftLibrary(),
|
178
|
|
- &outline,
|
|
274
|
+ &outline_,
|
179
|
275
|
&bitmap);
|
180
|
276
|
if (error)
|
181
|
277
|
{
|
182
|
278
|
// XXX error handling
|
183
|
|
- FT_Outline_Done(engine_->ftLibrary(), &outline);
|
184
|
279
|
return true;
|
185
|
280
|
}
|
186
|
281
|
|
... |
... |
@@ -189,12 +284,59 @@ GlyphContinuous::paintChar(QPainter* painter, |
189
|
284
|
image.convertToFormat(QImage::Format_ARGB32_Premultiplied));
|
190
|
285
|
|
191
|
286
|
x_ += width;
|
|
287
|
+
|
|
288
|
+ return true;
|
|
289
|
+}
|
|
290
|
+
|
192
|
291
|
|
193
|
|
- FT_Outline_Done(engine_->ftLibrary(), &outline);
|
|
292
|
+bool
|
|
293
|
+GlyphContinuous::loadGlyph(int index)
|
|
294
|
+{
|
|
295
|
+ glyph_ = engine_->loadGlyphWithoutUpdate(index);
|
|
296
|
+ isGlyphCloned_ = false;
|
|
297
|
+ if (!glyph_)
|
|
298
|
+ return false;
|
|
299
|
+ if (glyph_->format == FT_GLYPH_FORMAT_OUTLINE)
|
|
300
|
+ {
|
|
301
|
+ isOutlineCloned_ = false;
|
|
302
|
+ outline_ = reinterpret_cast<FT_OutlineGlyph>(glyph_)->outline;
|
|
303
|
+ }
|
194
|
304
|
return true;
|
195
|
305
|
}
|
196
|
306
|
|
197
|
307
|
|
|
308
|
+void
|
|
309
|
+GlyphContinuous::cloneGlyph()
|
|
310
|
+{
|
|
311
|
+ glyph_ = ::cloneGlyph(glyph_);
|
|
312
|
+ isGlyphCloned_ = true;
|
|
313
|
+}
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+void
|
|
317
|
+GlyphContinuous::cloneOutline()
|
|
318
|
+{
|
|
319
|
+ outline_ = ::cloneOutline(engine_->ftLibrary(), &outline_);
|
|
320
|
+ isOutlineCloned_ = true;
|
|
321
|
+}
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+void
|
|
325
|
+GlyphContinuous::cleanCloned()
|
|
326
|
+{
|
|
327
|
+ if (isGlyphCloned_)
|
|
328
|
+ {
|
|
329
|
+ FT_Done_Glyph(glyph_);
|
|
330
|
+ isGlyphCloned_ = false;
|
|
331
|
+ }
|
|
332
|
+ if (isOutlineCloned_)
|
|
333
|
+ {
|
|
334
|
+ FT_Outline_Done(engine_->ftLibrary(), &outline_);
|
|
335
|
+ isOutlineCloned_ = false;
|
|
336
|
+ }
|
|
337
|
+}
|
|
338
|
+
|
|
339
|
+
|
198
|
340
|
bool
|
199
|
341
|
GlyphContinuous::checkFitX(int x)
|
200
|
342
|
{
|
src/ftinspect/rendering/glyphcontinuous.hpp
... |
... |
@@ -7,6 +7,9 @@ |
7
|
7
|
#include "graphicsdefault.hpp"
|
8
|
8
|
#include <QWidget>
|
9
|
9
|
#include <freetype/freetype.h>
|
|
10
|
+#include <freetype/ftglyph.h>
|
|
11
|
+#include <freetype/ftoutln.h>
|
|
12
|
+#include <freetype/ftstroke.h>
|
10
|
13
|
|
11
|
14
|
class Engine;
|
12
|
15
|
class GlyphContinuous
|
... |
... |
@@ -15,7 +18,7 @@ class GlyphContinuous |
15
|
18
|
Q_OBJECT
|
16
|
19
|
public:
|
17
|
20
|
GlyphContinuous(QWidget* parent, Engine* engine);
|
18
|
|
- ~GlyphContinuous() override = default;
|
|
21
|
+ ~GlyphContinuous() override;
|
19
|
22
|
|
20
|
23
|
enum Mode : int
|
21
|
24
|
{
|
... |
... |
@@ -39,6 +42,13 @@ public: |
39
|
42
|
void setCharMapIndex(int index) { charMapIndex_ = index; }
|
40
|
43
|
void setMode(Mode mode) { mode_ = mode; }
|
41
|
44
|
void setSubModeAllGlyphs(SubModeAllGlyphs modeAg) { modeAG_ = modeAg; }
|
|
45
|
+ void setFancyParams(double boldX, double boldY, double slant)
|
|
46
|
+ {
|
|
47
|
+ boldX_ = boldX;
|
|
48
|
+ boldY_ = boldY;
|
|
49
|
+ slant_ = slant;
|
|
50
|
+ }
|
|
51
|
+ void setStrokeRadius(double radius) { strokeRadius_ = radius; }
|
42
|
52
|
|
43
|
53
|
signals:
|
44
|
54
|
void wheelNavigate(int steps);
|
... |
... |
@@ -53,21 +63,36 @@ private: |
53
|
63
|
Engine* engine_;
|
54
|
64
|
GraphicsDefault* graphicsDefault_;
|
55
|
65
|
|
|
66
|
+ Mode mode_ = AllGlyphs;
|
|
67
|
+ SubModeAllGlyphs modeAG_ = AG_AllGlyphs;
|
56
|
68
|
int beginIndex_;
|
57
|
69
|
int limitIndex_;
|
58
|
70
|
int charMapIndex_;
|
59
|
|
- Mode mode_ = AllGlyphs;
|
60
|
|
- SubModeAllGlyphs modeAG_ = AG_AllGlyphs;
|
|
71
|
+ double boldX_, boldY_, slant_;
|
|
72
|
+ double strokeRadius_;
|
61
|
73
|
|
62
|
74
|
int displayingCount_ = 0;
|
63
|
75
|
FT_Size_Metrics metrics_;
|
64
|
76
|
int x_ = 0, y_ = 0;
|
65
|
77
|
int stepY_ = 0;
|
|
78
|
+ FT_Glyph glyph_;
|
|
79
|
+ FT_Outline outline_;
|
|
80
|
+ // when glyph is cloned, outline is factually also cloned
|
|
81
|
+ // but `isOutlineCloned` won't be set!
|
|
82
|
+ bool isGlyphCloned_ = false, isOutlineCloned_ = false;
|
|
83
|
+
|
|
84
|
+ FT_Stroker stroker_;
|
66
|
85
|
|
67
|
|
- void paintAGAllGlyphs(QPainter* painter);
|
|
86
|
+ void paintAG(QPainter* painter);
|
|
87
|
+ void transformGlyphAGFancy();
|
|
88
|
+ void transformGlyphAGStroked();
|
68
|
89
|
void prePaint();
|
69
|
90
|
// return if there's enough space to paint the current char
|
70
|
|
- bool paintChar(QPainter* painter, int index);
|
|
91
|
+ bool paintChar(QPainter* painter);
|
|
92
|
+ bool loadGlyph(int index);
|
|
93
|
+ void cloneGlyph();
|
|
94
|
+ void cloneOutline();
|
|
95
|
+ void cleanCloned();
|
71
|
96
|
|
72
|
97
|
bool checkFitX(int x);
|
73
|
98
|
bool checkFitY(int y);
|
src/ftinspect/rendering/glyphoutline.cpp
... |
... |
@@ -88,10 +88,16 @@ static FT_Outline_Funcs outlineFuncs = |
88
|
88
|
|
89
|
89
|
|
90
|
90
|
GlyphOutline::GlyphOutline(const QPen& pen,
|
91
|
|
- FT_Outline* outline)
|
92
|
|
-: outlinePen_(pen),
|
93
|
|
- outline_(outline)
|
|
91
|
+ FT_Glyph glyph)
|
|
92
|
+: outlinePen_(pen)
|
94
|
93
|
{
|
|
94
|
+ if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
95
|
+ {
|
|
96
|
+ outline_ = NULL;
|
|
97
|
+ return;
|
|
98
|
+ }
|
|
99
|
+ outline_ = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
|
|
100
|
+
|
95
|
101
|
FT_BBox cbox;
|
96
|
102
|
|
97
|
103
|
qreal halfPenWidth = outlinePen_.widthF();
|
... |
... |
@@ -117,6 +123,8 @@ GlyphOutline::paint(QPainter* painter, |
117
|
123
|
const QStyleOptionGraphicsItem*,
|
118
|
124
|
QWidget*)
|
119
|
125
|
{
|
|
126
|
+ if (!outline_)
|
|
127
|
+ return;
|
120
|
128
|
painter->setPen(outlinePen_);
|
121
|
129
|
|
122
|
130
|
QPainterPath path;
|
src/ftinspect/rendering/glyphoutline.hpp
... |
... |
@@ -10,6 +10,7 @@ |
10
|
10
|
|
11
|
11
|
#include <ft2build.h>
|
12
|
12
|
#include <freetype/freetype.h>
|
|
13
|
+#include <freetype/ftglyph.h>
|
13
|
14
|
#include <freetype/ftoutln.h>
|
14
|
15
|
|
15
|
16
|
|
... |
... |
@@ -18,7 +19,7 @@ class GlyphOutline |
18
|
19
|
{
|
19
|
20
|
public:
|
20
|
21
|
GlyphOutline(const QPen& pen,
|
21
|
|
- FT_Outline* outline);
|
|
22
|
+ FT_Glyph glyph);
|
22
|
23
|
QRectF boundingRect() const override;
|
23
|
24
|
void paint(QPainter* painter,
|
24
|
25
|
const QStyleOptionGraphicsItem* option,
|
src/ftinspect/rendering/glyphpointnumbers.cpp
... |
... |
@@ -12,11 +12,17 @@ |
12
|
12
|
|
13
|
13
|
GlyphPointNumbers::GlyphPointNumbers(const QPen& onP,
|
14
|
14
|
const QPen& offP,
|
15
|
|
- FT_Outline* outln)
|
|
15
|
+ FT_Glyph glyph)
|
16
|
16
|
: onPen_(onP),
|
17
|
|
- offPen_(offP),
|
18
|
|
- outline_(outln)
|
|
17
|
+ offPen_(offP)
|
19
|
18
|
{
|
|
19
|
+ if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
20
|
+ {
|
|
21
|
+ outline_ = NULL;
|
|
22
|
+ return;
|
|
23
|
+ }
|
|
24
|
+ outline_ = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
|
|
25
|
+
|
20
|
26
|
FT_BBox cbox;
|
21
|
27
|
|
22
|
28
|
FT_Outline_Get_CBox(outline_, &cbox);
|
... |
... |
@@ -41,6 +47,8 @@ GlyphPointNumbers::paint(QPainter* painter, |
41
|
47
|
const QStyleOptionGraphicsItem* option,
|
42
|
48
|
QWidget*)
|
43
|
49
|
{
|
|
50
|
+ if (!outline_)
|
|
51
|
+ return;
|
44
|
52
|
const qreal lod = option->levelOfDetailFromTransform(
|
45
|
53
|
painter->worldTransform());
|
46
|
54
|
|
src/ftinspect/rendering/glyphpointnumbers.hpp
... |
... |
@@ -10,6 +10,7 @@ |
10
|
10
|
|
11
|
11
|
#include <ft2build.h>
|
12
|
12
|
#include <freetype/freetype.h>
|
|
13
|
+#include <freetype/ftglyph.h>
|
13
|
14
|
#include <freetype/ftoutln.h>
|
14
|
15
|
|
15
|
16
|
|
... |
... |
@@ -19,7 +20,7 @@ class GlyphPointNumbers |
19
|
20
|
public:
|
20
|
21
|
GlyphPointNumbers(const QPen& onPen,
|
21
|
22
|
const QPen& offPen,
|
22
|
|
- FT_Outline* outline);
|
|
23
|
+ FT_Glyph glyph);
|
23
|
24
|
QRectF boundingRect() const override;
|
24
|
25
|
void paint(QPainter* painter,
|
25
|
26
|
const QStyleOptionGraphicsItem* option,
|
src/ftinspect/rendering/glyphpoints.cpp
... |
... |
@@ -11,11 +11,17 @@ |
11
|
11
|
|
12
|
12
|
GlyphPoints::GlyphPoints(const QPen& onP,
|
13
|
13
|
const QPen& offP,
|
14
|
|
- FT_Outline* outln)
|
|
14
|
+ FT_Glyph glyph)
|
15
|
15
|
: onPen_(onP),
|
16
|
|
- offPen_(offP),
|
17
|
|
- outline_(outln)
|
|
16
|
+ offPen_(offP)
|
18
|
17
|
{
|
|
18
|
+ if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
19
|
+ {
|
|
20
|
+ outline_ = NULL;
|
|
21
|
+ return;
|
|
22
|
+ }
|
|
23
|
+ outline_ = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
|
|
24
|
+
|
19
|
25
|
FT_BBox cbox;
|
20
|
26
|
|
21
|
27
|
qreal halfPenWidth = qMax(onPen_.widthF(), offPen_.widthF()) / 2;
|
... |
... |
@@ -41,6 +47,9 @@ GlyphPoints::paint(QPainter* painter, |
41
|
47
|
const QStyleOptionGraphicsItem* option,
|
42
|
48
|
QWidget*)
|
43
|
49
|
{
|
|
50
|
+ if (!outline_)
|
|
51
|
+ return;
|
|
52
|
+
|
44
|
53
|
const qreal lod = option->levelOfDetailFromTransform(
|
45
|
54
|
painter->worldTransform());
|
46
|
55
|
|
src/ftinspect/rendering/glyphpoints.hpp
... |
... |
@@ -10,6 +10,7 @@ |
10
|
10
|
|
11
|
11
|
#include <ft2build.h>
|
12
|
12
|
#include <freetype/freetype.h>
|
|
13
|
+#include <freetype/ftglyph.h>
|
13
|
14
|
#include <freetype/ftoutln.h>
|
14
|
15
|
|
15
|
16
|
|
... |
... |
@@ -19,7 +20,7 @@ class GlyphPoints |
19
|
20
|
public:
|
20
|
21
|
GlyphPoints(const QPen& onPen,
|
21
|
22
|
const QPen& offPen,
|
22
|
|
- FT_Outline* outline);
|
|
23
|
+ FT_Glyph glyph);
|
23
|
24
|
QRectF boundingRect() const override;
|
24
|
25
|
void paint(QPainter* painter,
|
25
|
26
|
const QStyleOptionGraphicsItem* option,
|
src/ftinspect/rendering/grid.hpp
... |
... |
@@ -6,6 +6,7 @@ |
6
|
6
|
#pragma once
|
7
|
7
|
|
8
|
8
|
#include <QGraphicsItem>
|
|
9
|
+#include <QGraphicsView>
|
9
|
10
|
#include <QPen>
|
10
|
11
|
|
11
|
12
|
class Grid
|
src/ftinspect/rendering/renderutils.cpp
... |
... |
@@ -5,16 +5,43 @@ |
5
|
5
|
#include "renderutils.hpp"
|
6
|
6
|
|
7
|
7
|
FT_Outline
|
8
|
|
-transformOutlineToOrigin(FT_Library library,
|
9
|
|
- FT_Outline* outline,
|
10
|
|
- FT_BBox* outControlBox)
|
|
8
|
+cloneOutline(FT_Library library,
|
|
9
|
+ FT_Outline* src)
|
11
|
10
|
{
|
12
|
11
|
FT_Outline transformed;
|
13
|
|
- FT_Outline_New(library,
|
14
|
|
- static_cast<unsigned int>(outline->n_points),
|
15
|
|
- outline->n_contours, &transformed);
|
16
|
|
- FT_Outline_Copy(outline, &transformed);
|
|
12
|
+ FT_Outline_New(library, static_cast<unsigned int>(src->n_points),
|
|
13
|
+ src->n_contours, &transformed);
|
|
14
|
+ FT_Outline_Copy(src, &transformed);
|
|
15
|
+ return transformed;
|
|
16
|
+}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+FT_Glyph
|
|
20
|
+cloneGlyph(FT_Glyph src)
|
|
21
|
+{
|
|
22
|
+ FT_Glyph target = NULL;
|
|
23
|
+ FT_Glyph_Copy(src, &target);
|
|
24
|
+ return target;
|
|
25
|
+}
|
|
26
|
+
|
17
|
27
|
|
|
28
|
+void
|
|
29
|
+transformOutlineToOrigin(FT_Outline* outline,
|
|
30
|
+ FT_BBox* outControlBox)
|
|
31
|
+{
|
|
32
|
+ FT_Pos x, y;
|
|
33
|
+ computeTransformationToOrigin(outline,
|
|
34
|
+ &x, &y,
|
|
35
|
+ outControlBox);
|
|
36
|
+ FT_Outline_Translate(outline, x, y);
|
|
37
|
+}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+void computeTransformationToOrigin(FT_Outline* outline,
|
|
41
|
+ FT_Pos* outXOffset,
|
|
42
|
+ FT_Pos* outYOffset,
|
|
43
|
+ FT_BBox* outControlBox)
|
|
44
|
+{
|
18
|
45
|
FT_BBox cbox;
|
19
|
46
|
FT_Outline_Get_CBox(outline, &cbox);
|
20
|
47
|
|
... |
... |
@@ -23,11 +50,12 @@ transformOutlineToOrigin(FT_Library library, |
23
|
50
|
cbox.xMax = (cbox.xMax + 63) & ~63;
|
24
|
51
|
cbox.yMax = (cbox.yMax + 63) & ~63;
|
25
|
52
|
// we shift the outline to the origin for rendering later on
|
26
|
|
- FT_Outline_Translate(&transformed, -cbox.xMin, -cbox.yMin);
|
27
|
|
-
|
|
53
|
+ if (outXOffset)
|
|
54
|
+ *outXOffset = -cbox.xMin;
|
|
55
|
+ if (outYOffset)
|
|
56
|
+ *outYOffset = -cbox.yMin;
|
28
|
57
|
if (outControlBox)
|
29
|
58
|
*outControlBox = cbox;
|
30
|
|
- return transformed;
|
31
|
59
|
}
|
32
|
60
|
|
33
|
61
|
|
src/ftinspect/rendering/renderutils.hpp
... |
... |
@@ -4,12 +4,20 @@ |
4
|
4
|
|
5
|
5
|
#pragma once
|
6
|
6
|
|
|
7
|
+#include <freetype/ftglyph.h>
|
7
|
8
|
#include <freetype/ftoutln.h>
|
8
|
9
|
|
9
|
10
|
// The constructed `outline` must be freed by the caller
|
10
|
|
-FT_Outline transformOutlineToOrigin(FT_Library library,
|
11
|
|
- FT_Outline* outline,
|
12
|
|
- FT_BBox* outControlBox);
|
|
11
|
+FT_Outline cloneOutline(FT_Library library, FT_Outline* src);
|
|
12
|
+FT_Glyph cloneGlyph(FT_Glyph src);
|
|
13
|
+
|
|
14
|
+void transformOutlineToOrigin(FT_Outline* outline,
|
|
15
|
+ FT_BBox* outControlBox);
|
|
16
|
+
|
|
17
|
+void computeTransformationToOrigin(FT_Outline* outline,
|
|
18
|
+ FT_Pos* outXOffset,
|
|
19
|
+ FT_Pos* outYOffset,
|
|
20
|
+ FT_BBox* outControlBox);
|
13
|
21
|
|
14
|
22
|
|
15
|
23
|
// end of renderutils.hpp |
src/ftinspect/widgets/glyphindexselector.cpp
... |
... |
@@ -111,12 +111,11 @@ GlyphIndexSelector::updateLabel() |
111
|
111
|
.arg(numberRenderer_(indexSpinBox_->maximum())));
|
112
|
112
|
else
|
113
|
113
|
indexLabel_->setText(
|
114
|
|
- QString("%1~%2\nCount: %3\nLimit: %4")
|
|
114
|
+ QString("%1~%2\nLimit: %4")
|
115
|
115
|
.arg(numberRenderer_(indexSpinBox_->value()))
|
116
|
116
|
.arg(numberRenderer_(
|
117
|
117
|
qBound(indexSpinBox_->value(),
|
118
|
118
|
indexSpinBox_->value() + showingCount_ - 1, INT_MAX)))
|
119
|
|
- .arg(showingCount_)
|
120
|
119
|
.arg(numberRenderer_(indexSpinBox_->maximum())));
|
121
|
120
|
}
|
122
|
121
|
|
... |
... |
@@ -142,7 +141,7 @@ GlyphIndexSelector::createLayout() |
142
|
141
|
indexSpinBox_->setFixedWidth(80);
|
143
|
142
|
indexSpinBox_->setWrapping(false);
|
144
|
143
|
|
145
|
|
- indexLabel_ = new QLabel("0\nCount: 0\nLimit: 0");
|
|
144
|
+ indexLabel_ = new QLabel("0\nLimit: 0");
|
146
|
145
|
indexLabel_->setMinimumWidth(200);
|
147
|
146
|
|
148
|
147
|
setButtonNarrowest(toStartButton_);
|
|