Commits:
17 changed files:
Changes:
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
|
|
... |
... |
@@ -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,12 +424,7 @@ 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
|
|
... |
... |
@@ -436,7 +433,8 @@ Engine::loadGlyphWithoutUpdate(int glyphIndex) |
436
|
433
|
{
|
437
|
434
|
// TODO bitmap fonts? color layered fonts?
|
438
|
435
|
FT_Glyph glyph;
|
439
|
|
- imageType_.flags |= FT_LOAD_NO_BITMAP;
|
|
436
|
+ if (!embeddedBitmap_)
|
|
437
|
+ imageType_.flags |= FT_LOAD_NO_BITMAP;
|
440
|
438
|
if (FTC_ImageCache_Lookup(imageCache_,
|
441
|
439
|
&imageType_,
|
442
|
440
|
glyphIndex,
|
... |
... |
@@ -451,6 +449,57 @@ Engine::loadGlyphWithoutUpdate(int glyphIndex) |
451
|
449
|
}
|
452
|
450
|
|
453
|
451
|
|
|
452
|
+bool
|
|
453
|
+Engine::glyphToBitmap(FT_Glyph src,
|
|
454
|
+ FT_Glyph* out)
|
|
455
|
+{
|
|
456
|
+ if (src->format == FT_GLYPH_FORMAT_BITMAP)
|
|
457
|
+ {
|
|
458
|
+ *out = src;
|
|
459
|
+ return false;
|
|
460
|
+ }
|
|
461
|
+ if (src->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
462
|
+ {
|
|
463
|
+ *out = NULL;
|
|
464
|
+ return false;
|
|
465
|
+ // TODO support SVG
|
|
466
|
+ }
|
|
467
|
+
|
|
468
|
+ if (src->format == FT_GLYPH_FORMAT_OUTLINE)
|
|
469
|
+ {
|
|
470
|
+ FT_Glyph out2 = src;
|
|
471
|
+ auto error = FT_Glyph_To_Bitmap(&out2,
|
|
472
|
+ static_cast<FT_Render_Mode>(renderMode_),
|
|
473
|
+ nullptr,
|
|
474
|
+ false);
|
|
475
|
+ if (error)
|
|
476
|
+ {
|
|
477
|
+ *out = NULL;
|
|
478
|
+ return false;
|
|
479
|
+ }
|
|
480
|
+ *out = out2;
|
|
481
|
+ return true;
|
|
482
|
+ }
|
|
483
|
+
|
|
484
|
+ *out = NULL;
|
|
485
|
+ return false;
|
|
486
|
+}
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+FT_Bitmap
|
|
490
|
+Engine::convertBitmapTo8Bpp(FT_Bitmap* bitmap)
|
|
491
|
+{
|
|
492
|
+ FT_Bitmap out;
|
|
493
|
+ out.buffer = NULL;
|
|
494
|
+ auto error = FT_Bitmap_Convert(library_, bitmap, &out, 1);
|
|
495
|
+ if (error)
|
|
496
|
+ {
|
|
497
|
+ // XXX handling?
|
|
498
|
+ }
|
|
499
|
+ return out;
|
|
500
|
+}
|
|
501
|
+
|
|
502
|
+
|
454
|
503
|
int
|
455
|
504
|
Engine::numberOfOpenedFonts()
|
456
|
505
|
{
|
... |
... |
@@ -527,19 +576,19 @@ Engine::update() |
527
|
576
|
loadFlags_ = FT_LOAD_DEFAULT;
|
528
|
577
|
if (doAutoHinting_)
|
529
|
578
|
loadFlags_ |= FT_LOAD_FORCE_AUTOHINT;
|
530
|
|
- loadFlags_ |= FT_LOAD_NO_BITMAP; // XXX handle bitmap fonts also
|
|
579
|
+
|
|
580
|
+ if (!embeddedBitmap_)
|
|
581
|
+ loadFlags_ |= FT_LOAD_NO_BITMAP;
|
531
|
582
|
|
532
|
583
|
if (doHinting_)
|
533
|
584
|
{
|
534
|
|
- // TODO Differentiate RGB/BGR here?
|
535
|
|
- unsigned long target = antiAliasingTarget_;
|
536
|
|
- loadFlags_ |= target;
|
|
585
|
+ loadFlags_ |= antiAliasingTarget_;
|
537
|
586
|
}
|
538
|
587
|
else
|
539
|
588
|
{
|
540
|
589
|
loadFlags_ |= FT_LOAD_NO_HINTING;
|
541
|
590
|
|
542
|
|
- if (!antiAliasingEnabled_) // XXX does this hold?
|
|
591
|
+ if (!antiAliasingEnabled_)
|
543
|
592
|
loadFlags_ |= FT_LOAD_MONOCHROME;
|
544
|
593
|
}
|
545
|
594
|
|
... |
... |
@@ -561,7 +610,7 @@ Engine::update() |
561
|
610
|
scaler_.x_res = dpi_;
|
562
|
611
|
scaler_.y_res = dpi_;
|
563
|
612
|
}
|
564
|
|
-
|
|
613
|
+
|
565
|
614
|
imageType_.width = static_cast<unsigned int>(pixelSize_);
|
566
|
615
|
imageType_.height = static_cast<unsigned int>(pixelSize_);
|
567
|
616
|
imageType_.flags = static_cast<int>(loadFlags_);
|
... |
... |
@@ -668,6 +717,197 @@ Engine::queryEngine() |
668
|
717
|
}
|
669
|
718
|
|
670
|
719
|
|
|
720
|
+void
|
|
721
|
+convertLCDToARGB(FT_Bitmap& bitmap,
|
|
722
|
+ QImage& image,
|
|
723
|
+ bool isBGR)
|
|
724
|
+{
|
|
725
|
+ // see gblany.h
|
|
726
|
+ // Optimize me: Use SIMD?
|
|
727
|
+ int height = bitmap.rows;
|
|
728
|
+ int width = bitmap.width / 3;
|
|
729
|
+ int width3 = bitmap.width;
|
|
730
|
+
|
|
731
|
+ unsigned char* srcPtr = bitmap.buffer;
|
|
732
|
+ unsigned* dstPtr = reinterpret_cast<unsigned*>(image.bits());
|
|
733
|
+
|
|
734
|
+ int offR = !isBGR ? 0 : 2;
|
|
735
|
+ int offG = 1;
|
|
736
|
+ int offB = isBGR ? 0 : 2;
|
|
737
|
+ for (int i = 0; i < height; i++)
|
|
738
|
+ {
|
|
739
|
+ for (int j = 0; j < width3; j += 3)
|
|
740
|
+ {
|
|
741
|
+ unsigned char ar = srcPtr[j + offR];
|
|
742
|
+ unsigned char ag = srcPtr[j + offG];
|
|
743
|
+ unsigned char ab = srcPtr[j + offB];
|
|
744
|
+ *dstPtr = (0xFFU << 24) | (ar << 16) | (ag << 8) | ab;
|
|
745
|
+ dstPtr++;
|
|
746
|
+ }
|
|
747
|
+ srcPtr += bitmap.pitch;
|
|
748
|
+ dstPtr += image.bytesPerLine() / 4 - width; // skip blank area
|
|
749
|
+ }
|
|
750
|
+}
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+void
|
|
754
|
+convertLCDVToARGB(FT_Bitmap& bitmap,
|
|
755
|
+ QImage& image,
|
|
756
|
+ bool isBGR)
|
|
757
|
+{
|
|
758
|
+ // see gblany.h
|
|
759
|
+ // Optimize me: Use SIMD?
|
|
760
|
+ int height = bitmap.rows / 3;
|
|
761
|
+ int width = bitmap.width;
|
|
762
|
+ int srcPitch = bitmap.pitch;
|
|
763
|
+
|
|
764
|
+ unsigned char* srcPtr = bitmap.buffer;
|
|
765
|
+ unsigned* dstPtr = reinterpret_cast<unsigned*>(image.bits());
|
|
766
|
+
|
|
767
|
+ int offR = !isBGR ? 0 : 2 * srcPitch;
|
|
768
|
+ int offG = srcPitch;
|
|
769
|
+ int offB = isBGR ? 0 : 2 * srcPitch;
|
|
770
|
+ for (int i = 0; i < height; i++)
|
|
771
|
+ {
|
|
772
|
+ for (int j = 0; j < width; j++)
|
|
773
|
+ {
|
|
774
|
+ unsigned char ar = srcPtr[j + offR];
|
|
775
|
+ unsigned char ag = srcPtr[j + offG];
|
|
776
|
+ unsigned char ab = srcPtr[j + offB];
|
|
777
|
+ *dstPtr = (0xFFU << 24) | (ar << 16) | (ag << 8) | ab;
|
|
778
|
+ dstPtr++;
|
|
779
|
+ }
|
|
780
|
+ srcPtr += 3ull * srcPitch; // move 3 lines
|
|
781
|
+ dstPtr += image.bytesPerLine() / 4 - width; // skip blank area
|
|
782
|
+ }
|
|
783
|
+}
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+QImage*
|
|
787
|
+Engine::convertBitmapToQImage(FT_Glyph src,
|
|
788
|
+ QRect* outRect)
|
|
789
|
+{
|
|
790
|
+ QImage* result = NULL;
|
|
791
|
+ FT_BitmapGlyph bitmapGlyph;
|
|
792
|
+ bool ownBitmapGlyph
|
|
793
|
+ = glyphToBitmap(src, reinterpret_cast<FT_Glyph*>(&bitmapGlyph));
|
|
794
|
+ if (!bitmapGlyph)
|
|
795
|
+ return result;
|
|
796
|
+ auto& bmap = bitmapGlyph->bitmap;
|
|
797
|
+ bool ownBitmap = false;
|
|
798
|
+
|
|
799
|
+ int width = bmap.width;
|
|
800
|
+ int height = bmap.rows;
|
|
801
|
+ QImage::Format format = QImage::Format_Indexed8; // goto crossing init
|
|
802
|
+
|
|
803
|
+ if (bmap.pixel_mode == FT_PIXEL_MODE_GRAY2
|
|
804
|
+ || bmap.pixel_mode == FT_PIXEL_MODE_GRAY4)
|
|
805
|
+ {
|
|
806
|
+ bmap = convertBitmapTo8Bpp(&bmap);
|
|
807
|
+ if (!bmap.buffer)
|
|
808
|
+ goto cleanup;
|
|
809
|
+ ownBitmap = true;
|
|
810
|
+ }
|
|
811
|
+
|
|
812
|
+ if (bmap.pixel_mode == FT_PIXEL_MODE_LCD)
|
|
813
|
+ width /= 3;
|
|
814
|
+ else if (bmap.pixel_mode == FT_PIXEL_MODE_LCD_V)
|
|
815
|
+ height /= 3;
|
|
816
|
+
|
|
817
|
+ if (outRect)
|
|
818
|
+ {
|
|
819
|
+ outRect->setLeft(bitmapGlyph->left);
|
|
820
|
+ outRect->setTop(-bitmapGlyph->top);
|
|
821
|
+ outRect->setWidth(width);
|
|
822
|
+ outRect->setHeight(height);
|
|
823
|
+ }
|
|
824
|
+
|
|
825
|
+ switch (bmap.pixel_mode)
|
|
826
|
+ {
|
|
827
|
+ case FT_PIXEL_MODE_MONO:
|
|
828
|
+ format = QImage::Format_Mono;
|
|
829
|
+ break;
|
|
830
|
+ case FT_PIXEL_MODE_GRAY:
|
|
831
|
+ format = QImage::Format_Indexed8;
|
|
832
|
+ break;
|
|
833
|
+ case FT_PIXEL_MODE_BGRA:
|
|
834
|
+ // XXX "ARGB" here means BGRA due to endianness - may be problematic
|
|
835
|
+ // on big-endian machines
|
|
836
|
+ format = QImage::Format_ARGB32_Premultiplied;
|
|
837
|
+ break;
|
|
838
|
+ case FT_PIXEL_MODE_LCD:
|
|
839
|
+ case FT_PIXEL_MODE_LCD_V:
|
|
840
|
+ format = QImage::Format_ARGB32;
|
|
841
|
+ break;
|
|
842
|
+ default:
|
|
843
|
+ goto cleanup;
|
|
844
|
+ }
|
|
845
|
+
|
|
846
|
+ switch (bmap.pixel_mode)
|
|
847
|
+ {
|
|
848
|
+ case FT_PIXEL_MODE_MONO:
|
|
849
|
+ case FT_PIXEL_MODE_GRAY:
|
|
850
|
+ case FT_PIXEL_MODE_BGRA:
|
|
851
|
+ {
|
|
852
|
+ QImage image(bmap.buffer,
|
|
853
|
+ width, height,
|
|
854
|
+ bmap.pitch,
|
|
855
|
+ format);
|
|
856
|
+ if (bmap.pixel_mode == FT_PIXEL_MODE_GRAY)
|
|
857
|
+ image.setColorTable(GraphicsDefault::deafultInstance()->grayColorTable);
|
|
858
|
+ else if (bmap.pixel_mode == FT_PIXEL_MODE_MONO)
|
|
859
|
+ image.setColorTable(GraphicsDefault::deafultInstance()->monoColorTable);
|
|
860
|
+ result = new QImage(image.copy());
|
|
861
|
+ // Don't directly use `image` since we're destroying the image
|
|
862
|
+ }
|
|
863
|
+ break;
|
|
864
|
+ case FT_PIXEL_MODE_LCD:;
|
|
865
|
+ result = new QImage(width, height, format);
|
|
866
|
+ convertLCDToARGB(bmap, *result, lcdUsesBGR_);
|
|
867
|
+ break;
|
|
868
|
+ case FT_PIXEL_MODE_LCD_V:;
|
|
869
|
+ result = new QImage(width, height, format);
|
|
870
|
+ convertLCDVToARGB(bmap, *result, lcdUsesBGR_);
|
|
871
|
+ break;
|
|
872
|
+ }
|
|
873
|
+
|
|
874
|
+cleanup:
|
|
875
|
+ if (ownBitmapGlyph)
|
|
876
|
+ FT_Done_Glyph(reinterpret_cast<FT_Glyph>(bitmapGlyph));
|
|
877
|
+ if (ownBitmap)
|
|
878
|
+ FT_Bitmap_Done(library_, &bmap);
|
|
879
|
+
|
|
880
|
+ return result;
|
|
881
|
+}
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+QHash<FT_Glyph_Format, QString> glyphFormatNamesCache;
|
|
885
|
+QHash<FT_Glyph_Format, QString>&
|
|
886
|
+glyphFormatNames()
|
|
887
|
+{
|
|
888
|
+ if (glyphFormatNamesCache.empty())
|
|
889
|
+ {
|
|
890
|
+ glyphFormatNamesCache[FT_GLYPH_FORMAT_NONE] = "None/Unknown";
|
|
891
|
+ glyphFormatNamesCache[FT_GLYPH_FORMAT_COMPOSITE] = "Composite";
|
|
892
|
+ glyphFormatNamesCache[FT_GLYPH_FORMAT_BITMAP] = "Bitmap";
|
|
893
|
+ glyphFormatNamesCache[FT_GLYPH_FORMAT_OUTLINE] = "Outline";
|
|
894
|
+ glyphFormatNamesCache[FT_GLYPH_FORMAT_PLOTTER] = "Plotter";
|
|
895
|
+ glyphFormatNamesCache[FT_GLYPH_FORMAT_SVG] = "SVG";
|
|
896
|
+ }
|
|
897
|
+ return glyphFormatNamesCache;
|
|
898
|
+}
|
|
899
|
+
|
|
900
|
+QString*
|
|
901
|
+glyphFormatToName(FT_Glyph_Format format)
|
|
902
|
+{
|
|
903
|
+ auto& names = glyphFormatNames();
|
|
904
|
+ auto it = names.find(format);
|
|
905
|
+ if (it == names.end())
|
|
906
|
+ return &names[FT_GLYPH_FORMAT_NONE];
|
|
907
|
+ return &it.value();
|
|
908
|
+}
|
|
909
|
+
|
|
910
|
+
|
671
|
911
|
QHash<FT_Encoding, QString> encodingNamesCache;
|
672
|
912
|
QHash<FT_Encoding, QString>&
|
673
|
913
|
encodingNames()
|
src/ftinspect/engine/engine.hpp
... |
... |
@@ -10,6 +10,8 @@ |
10
|
10
|
#include <vector>
|
11
|
11
|
#include <QString>
|
12
|
12
|
#include <QMap>
|
|
13
|
+#include <QRect>
|
|
14
|
+#include <QImage>
|
13
|
15
|
|
14
|
16
|
#include <ft2build.h>
|
15
|
17
|
#include <freetype/freetype.h>
|
... |
... |
@@ -60,6 +62,10 @@ private: |
60
|
62
|
static int maxIndexForFaceAndCharMap(FT_CharMap charMap, unsigned max);
|
61
|
63
|
};
|
62
|
64
|
|
|
65
|
+// Some helper functions.
|
|
66
|
+
|
|
67
|
+QString* glyphFormatToName(FT_Glyph_Format format);
|
|
68
|
+
|
63
|
69
|
// FreeType specific data.
|
64
|
70
|
|
65
|
71
|
class Engine
|
... |
... |
@@ -92,11 +98,18 @@ public: |
92
|
98
|
int loadFont(int fontIndex,
|
93
|
99
|
long faceIndex,
|
94
|
100
|
int namedInstanceIndex); // return number of glyphs
|
95
|
|
- FT_Outline* loadOutline(int glyphIndex);
|
|
101
|
+ //FT_Outline* loadOutline(int glyphIndex);
|
|
102
|
+ FT_Glyph loadGlyph(int glyphIndex);
|
96
|
103
|
|
97
|
104
|
// Sometimes the engine is already updated, and we want to be faster
|
98
|
105
|
FT_Glyph loadGlyphWithoutUpdate(int glyphIndex);
|
99
|
106
|
|
|
107
|
+ // Return `true` if you need to free `out`
|
|
108
|
+ // `out` will be set to NULL in cases of error
|
|
109
|
+ bool glyphToBitmap(FT_Glyph src, FT_Glyph* out);
|
|
110
|
+ FT_Bitmap convertBitmapTo8Bpp(FT_Bitmap* bitmap);
|
|
111
|
+ QImage* convertBitmapToQImage(FT_Glyph src, QRect* outRect);
|
|
112
|
+
|
100
|
113
|
// reload current triplet, but with updated settings, useful for updating
|
101
|
114
|
// `ftSize_` only
|
102
|
115
|
void reloadFont();
|
... |
... |
@@ -126,7 +139,7 @@ public: |
126
|
139
|
FontFileManager& fontFileManager() { return fontFileManager_; }
|
127
|
140
|
EngineDefaultValues& engineDefaults() { return engineDefaults_; }
|
128
|
141
|
bool antiAliasingEnabled() { return antiAliasingEnabled_; }
|
129
|
|
-
|
|
142
|
+ bool embeddedBitmapEnabled() { return embeddedBitmap_; }
|
130
|
143
|
|
131
|
144
|
//////// Setters (direct or indirect)
|
132
|
145
|
|
... |
... |
@@ -150,7 +163,10 @@ public: |
150
|
163
|
void setShowSegments(bool showSegments) { showSegments_ = showSegments; }
|
151
|
164
|
void setGamma(double gamma) { gamma_ = gamma; }
|
152
|
165
|
void setAntiAliasingTarget(int target) { antiAliasingTarget_ = target; }
|
|
166
|
+ void setRenderMode(int mode) { renderMode_ = mode; }
|
153
|
167
|
void setAntiAliasingEnabled(bool enabled) { antiAliasingEnabled_ = enabled; }
|
|
168
|
+ void setEmbeddedBitmap(bool force) { embeddedBitmap_ = force; }
|
|
169
|
+ void setLCDUsesBGR(bool isBGR) { lcdUsesBGR_ = isBGR; }
|
154
|
170
|
|
155
|
171
|
// Note: These 3 functions now takes actual mode/version from FreeType,
|
156
|
172
|
// instead of values from enum in MainGUI!
|
... |
... |
@@ -203,10 +219,12 @@ private: |
203
|
219
|
bool doVerticalHinting_;
|
204
|
220
|
bool doBlueZoneHinting_;
|
205
|
221
|
bool showSegments_;
|
|
222
|
+ bool embeddedBitmap_;
|
206
|
223
|
int antiAliasingTarget_;
|
|
224
|
+ bool lcdUsesBGR_;
|
|
225
|
+ int renderMode_;
|
207
|
226
|
|
208
|
227
|
double gamma_;
|
209
|
|
-
|
210
|
228
|
unsigned long loadFlags_;
|
211
|
229
|
|
212
|
230
|
void queryEngine();
|
src/ftinspect/models/ttsettingscomboboxmodel.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
... |
... |
@@ -71,25 +71,45 @@ 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
|
+ }
|
|
92
|
+
|
|
93
|
+ virtual QVariant
|
|
94
|
+ data(const QModelIndex& index,
|
|
95
|
+ int role) const
|
|
96
|
+ {
|
|
97
|
+ if (role != Qt::DisplayRole)
|
|
98
|
+ return QVariant{};
|
91
|
99
|
|
92
|
|
- int indexToValue(int index);
|
|
100
|
+ int r = index.row();
|
|
101
|
+ if (r < 0 || r >= items_.size())
|
|
102
|
+ return QVariant{};
|
|
103
|
+ return items_[r].displayName;
|
|
104
|
+ }
|
|
105
|
+
|
|
106
|
+ virtual T
|
|
107
|
+ indexToValue(int index)
|
|
108
|
+ {
|
|
109
|
+ if (index < 0 || index >= items_.size())
|
|
110
|
+ return T();
|
|
111
|
+ return items_[index].value;
|
|
112
|
+ }
|
93
|
113
|
|
94
|
114
|
protected:
|
95
|
115
|
QHash<int, ComboBoxItem> items_;
|
... |
... |
@@ -97,7 +117,8 @@ protected: |
97
|
117
|
|
98
|
118
|
|
99
|
119
|
class LCDFilterComboBoxModel
|
100
|
|
-: public SimpleComboBoxModel
|
|
120
|
+: public QAbstractListModel,
|
|
121
|
+ public SimpleComboBoxModelImpl<int>
|
101
|
122
|
{
|
102
|
123
|
Q_OBJECT
|
103
|
124
|
public:
|
... |
... |
@@ -111,6 +132,17 @@ public: |
111
|
132
|
explicit LCDFilterComboBoxModel(QObject* parent);
|
112
|
133
|
virtual ~LCDFilterComboBoxModel() = default;
|
113
|
134
|
|
|
135
|
+ int rowCount(const QModelIndex& parent) const override
|
|
136
|
+ {
|
|
137
|
+ return SimpleComboBoxModelImpl::rowCount(parent);
|
|
138
|
+ }
|
|
139
|
+ QVariant
|
|
140
|
+ data(const QModelIndex& index,
|
|
141
|
+ int role) const override
|
|
142
|
+ {
|
|
143
|
+ return SimpleComboBoxModelImpl::data(index, role);
|
|
144
|
+ }
|
|
145
|
+
|
114
|
146
|
public:
|
115
|
147
|
enum LCDFilter : int
|
116
|
148
|
{
|
... |
... |
@@ -122,8 +154,18 @@ public: |
122
|
154
|
};
|
123
|
155
|
|
124
|
156
|
|
|
157
|
+struct AASetting
|
|
158
|
+{
|
|
159
|
+ // No default value for braced init - No C++14, what a pain!
|
|
160
|
+ int lcdFilter;
|
|
161
|
+ int renderMode;
|
|
162
|
+ bool isBGR;
|
|
163
|
+};
|
|
164
|
+
|
|
165
|
+
|
125
|
166
|
class AntiAliasingComboBoxModel
|
126
|
|
-: public SimpleComboBoxModel
|
|
167
|
+: public QAbstractListModel,
|
|
168
|
+ public SimpleComboBoxModelImpl<AASetting>
|
127
|
169
|
{
|
128
|
170
|
Q_OBJECT
|
129
|
171
|
public:
|
... |
... |
@@ -135,6 +177,11 @@ public: |
135
|
177
|
QVariant data(const QModelIndex& index,
|
136
|
178
|
int role) const;
|
137
|
179
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
|
180
|
+ using SimpleComboBoxModelImpl::rowCount;
|
|
181
|
+ int rowCount(const QModelIndex& parent) const override
|
|
182
|
+ {
|
|
183
|
+ return SimpleComboBoxModelImpl::rowCount(parent);
|
|
184
|
+ }
|
138
|
185
|
|
139
|
186
|
void setLightAntiAliasingEnabled(bool enabled)
|
140
|
187
|
{
|
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.lcdFilter);
|
|
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,34 +6,27 @@ |
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)
|
|
19
|
+: engine_(engine),
|
|
20
|
+ library_(engine->ftLibrary())
|
24
|
21
|
{
|
25
|
|
- // make a copy of the outline since we are going to manipulate it
|
26
|
|
- FT_BBox cbox;
|
27
|
|
- transformed_ = cloneOutline(lib, outline);
|
28
|
|
- transformOutlineToOrigin(&transformed_, &cbox);
|
29
|
|
- boundingRect_.setCoords(cbox.xMin / 64, -cbox.yMax / 64,
|
30
|
|
- cbox.xMax / 64, -cbox.yMin / 64);
|
|
22
|
+ QRect bRect;
|
|
23
|
+ image_ = engine_->convertBitmapToQImage(glyph, &bRect);
|
|
24
|
+ boundingRect_ = bRect; // QRectF to QRect
|
31
|
25
|
}
|
32
|
26
|
|
33
|
27
|
|
34
|
28
|
GlyphBitmap::~GlyphBitmap()
|
35
|
29
|
{
|
36
|
|
- FT_Outline_Done(library_, &transformed_);
|
37
|
30
|
}
|
38
|
31
|
|
39
|
32
|
QRectF
|
... |
... |
@@ -48,40 +41,9 @@ GlyphBitmap::paint(QPainter* painter, |
48
|
41
|
const QStyleOptionGraphicsItem* option,
|
49
|
42
|
QWidget*)
|
50
|
43
|
{
|
51
|
|
- FT_Bitmap bitmap;
|
52
|
|
-
|
53
|
|
- int height = static_cast<int>(ceil(boundingRect_.height()));
|
54
|
|
- int width = static_cast<int>(ceil(boundingRect_.width()));
|
55
|
|
- QImage::Format format = QImage::Format_Indexed8;
|
56
|
|
-
|
57
|
|
- // XXX cover LCD and color
|
58
|
|
- if (pixelMode_ == FT_PIXEL_MODE_MONO)
|
59
|
|
- format = QImage::Format_Mono;
|
60
|
|
-
|
61
|
|
- QImage image(QSize(width, height), format);
|
62
|
|
-
|
63
|
|
- if (pixelMode_ == FT_PIXEL_MODE_MONO)
|
64
|
|
- image.setColorTable(monoColorTable_);
|
65
|
|
- else
|
66
|
|
- image.setColorTable(grayColorTable_);
|
67
|
|
-
|
68
|
|
- image.fill(0);
|
69
|
|
-
|
70
|
|
- bitmap.rows = static_cast<unsigned int>(height);
|
71
|
|
- bitmap.width = static_cast<unsigned int>(width);
|
72
|
|
- bitmap.buffer = image.bits();
|
73
|
|
- bitmap.pitch = image.bytesPerLine();
|
74
|
|
- bitmap.pixel_mode = pixelMode_;
|
75
|
|
-
|
76
|
|
- FT_Error error = FT_Outline_Get_Bitmap(library_,
|
77
|
|
- &transformed_,
|
78
|
|
- &bitmap);
|
79
|
|
- if (error)
|
80
|
|
- {
|
81
|
|
- // XXX error handling
|
|
44
|
+ if (!image_)
|
82
|
45
|
return;
|
83
|
|
- }
|
84
|
|
-
|
|
46
|
+
|
85
|
47
|
// `drawImage' doesn't work as expected:
|
86
|
48
|
// the larger the zoom, the more the pixel rectangle positions
|
87
|
49
|
// deviate from the grid lines
|
... |
... |
@@ -95,11 +57,11 @@ GlyphBitmap::paint(QPainter* painter, |
95
|
57
|
|
96
|
58
|
painter->setPen(Qt::NoPen);
|
97
|
59
|
|
98
|
|
- for (int x = 0; x < image.width(); x++)
|
99
|
|
- for (int y = 0; y < image.height(); y++)
|
|
60
|
+ for (int x = 0; x < image_->width(); x++)
|
|
61
|
+ for (int y = 0; y < image_->height(); y++)
|
100
|
62
|
{
|
101
|
63
|
// be careful not to lose the alpha channel
|
102
|
|
- QRgb p = image.pixel(x, y);
|
|
64
|
+ QRgb p = image_->pixel(x, y);
|
103
|
65
|
painter->fillRect(QRectF(x + boundingRect_.left() - 1 / lod / 2,
|
104
|
66
|
y + boundingRect_.top() - 1 / lod / 2,
|
105
|
67
|
1 + 1 / lod,
|
... |
... |
@@ -109,7 +71,9 @@ GlyphBitmap::paint(QPainter* painter, |
109
|
71
|
qBlue(p),
|
110
|
72
|
qAlpha(p)));
|
111
|
73
|
}
|
|
74
|
+
|
112
|
75
|
#endif
|
|
76
|
+
|
113
|
77
|
}
|
114
|
78
|
|
115
|
79
|
|
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,9 @@ public: |
29
|
29
|
QWidget* widget) override;
|
30
|
30
|
|
31
|
31
|
private:
|
32
|
|
- FT_Outline transformed_;
|
|
32
|
+ Engine* engine_;
|
|
33
|
+ QImage* image_ = NULL;
|
33
|
34
|
FT_Library library_;
|
34
|
|
- unsigned char pixelMode_;
|
35
|
|
- const QVector<QRgb>& monoColorTable_;
|
36
|
|
- const QVector<QRgb>& grayColorTable_;
|
37
|
35
|
QRectF boundingRect_;
|
38
|
36
|
};
|
39
|
37
|
|
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/renderutils.cpp
... |
... |
@@ -28,6 +28,19 @@ cloneGlyph(FT_Glyph src) |
28
|
28
|
void
|
29
|
29
|
transformOutlineToOrigin(FT_Outline* outline,
|
30
|
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)
|
31
|
44
|
{
|
32
|
45
|
FT_BBox cbox;
|
33
|
46
|
FT_Outline_Get_CBox(outline, &cbox);
|
... |
... |
@@ -37,8 +50,10 @@ transformOutlineToOrigin(FT_Outline* outline, |
37
|
50
|
cbox.xMax = (cbox.xMax + 63) & ~63;
|
38
|
51
|
cbox.yMax = (cbox.yMax + 63) & ~63;
|
39
|
52
|
// we shift the outline to the origin for rendering later on
|
40
|
|
- FT_Outline_Translate(outline, -cbox.xMin, -cbox.yMin);
|
41
|
|
-
|
|
53
|
+ if (outXOffset)
|
|
54
|
+ *outXOffset = -cbox.xMin;
|
|
55
|
+ if (outYOffset)
|
|
56
|
+ *outYOffset = -cbox.yMin;
|
42
|
57
|
if (outControlBox)
|
43
|
58
|
*outControlBox = cbox;
|
44
|
59
|
}
|
src/ftinspect/rendering/renderutils.hpp
... |
... |
@@ -14,5 +14,10 @@ FT_Glyph cloneGlyph(FT_Glyph src); |
14
|
14
|
void transformOutlineToOrigin(FT_Outline* outline,
|
15
|
15
|
FT_BBox* outControlBox);
|
16
|
16
|
|
|
17
|
+void computeTransformationToOrigin(FT_Outline* outline,
|
|
18
|
+ FT_Pos* outXOffset,
|
|
19
|
+ FT_Pos* outYOffset,
|
|
20
|
+ FT_BBox* outControlBox);
|
|
21
|
+
|
17
|
22
|
|
18
|
23
|
// end of renderutils.hpp |
|