Commits:
-
4509eebf
by Charlie Jiang
at 2022-09-06T13:39:47+08:00
* src/ftinspect/engine/stringrenderer.cpp: Further fix infinite loop.
-
da225fd7
by Charlie Jiang
at 2022-09-07T10:56:54+08:00
[ftinspect] Improve bitmap display in the glyph details pane.
Now the ppem square is displayed as red, and the actual bitmaps is drawn
with blue border. The whole bounding box is black.
Adding ppem square improves displaying of non-spacing glyphs.
* src/ftinspect/panels/glyphdetails.cpp:
Add ppem square and properly position the bitmap.
* src/ftinspect/glyphcomponents/glyphbitmap.cpp,
src/ftinspect/glyphcomponents/glyphbitmap.hpp:
Add a `placeholderRect` to store the ppem square info. Layout the glyph
bitmap on the basis of the ppem square.
4 changed files:
Changes:
src/ftinspect/engine/stringrenderer.cpp
... |
... |
@@ -505,9 +505,13 @@ StringRenderer::render(int width, |
505
|
505
|
auto stepY = static_cast<int>(metrics.height >> 6) + 1;
|
506
|
506
|
y += 4 + static_cast<int>(metrics.ascender >> 6);
|
507
|
507
|
|
|
508
|
+ auto lastOffset = 0;
|
508
|
509
|
while (offset < static_cast<int>(activeGlyphs_.size()))
|
509
|
510
|
{
|
510
|
511
|
offset = renderLine(x, y, width, height, offset, true);
|
|
512
|
+ if (offset == lastOffset) // prevent inf loop.
|
|
513
|
+ break;
|
|
514
|
+ lastOffset = offset;
|
511
|
515
|
y += stepY;
|
512
|
516
|
}
|
513
|
517
|
return offset - initialOffset;
|
... |
... |
@@ -522,6 +526,9 @@ StringRenderer::renderLine(int x, |
522
|
526
|
int offset,
|
523
|
527
|
bool handleMultiLine)
|
524
|
528
|
{
|
|
529
|
+ // Don't limit the x y to be within the canvas viewport: string can be moved
|
|
530
|
+ // by the mouse
|
|
531
|
+
|
525
|
532
|
y = height - y; // change to Cartesian coordinates
|
526
|
533
|
|
527
|
534
|
FT_Vector pen = { 0, 0 };
|
src/ftinspect/glyphcomponents/glyphbitmap.cpp
... |
... |
@@ -107,14 +107,17 @@ GlyphBitmapWidget::~GlyphBitmapWidget() |
107
|
107
|
|
108
|
108
|
void
|
109
|
109
|
GlyphBitmapWidget::updateImage(QImage* image,
|
110
|
|
- QRect rect)
|
|
110
|
+ QRect rect,
|
|
111
|
+ QRect placeholderRect)
|
111
|
112
|
{
|
112
|
|
- rect.moveTop(0);
|
113
|
|
- rect.moveLeft(0);
|
114
|
|
-
|
115
|
113
|
delete bitmapItem_;
|
116
|
114
|
auto* copied = new QImage(image->copy());
|
117
|
|
- bitmapItem_ = new GlyphBitmap(copied, rect);
|
|
115
|
+
|
|
116
|
+ rect_ = rect;
|
|
117
|
+ placeholderRect_ = placeholderRect;
|
|
118
|
+ auto zeroedRect = rect; // `GlyphBitmap` doesn't play well with offset
|
|
119
|
+ zeroedRect.moveTopLeft({ 0, 0 });
|
|
120
|
+ bitmapItem_ = new GlyphBitmap(copied, zeroedRect);
|
118
|
121
|
|
119
|
122
|
repaint();
|
120
|
123
|
}
|
... |
... |
@@ -135,24 +138,44 @@ GlyphBitmapWidget::paintEvent(QPaintEvent* event) |
135
|
138
|
if (!bitmapItem_)
|
136
|
139
|
return;
|
137
|
140
|
auto s = size();
|
138
|
|
- auto br = bitmapItem_->boundingRect();
|
139
|
|
- double xScale = s.width() / br.width();
|
140
|
|
- double yScale = s.height() / br.height();
|
|
141
|
+
|
|
142
|
+ auto br = QRect(QPoint(std::min(rect_.left(), placeholderRect_.left()),
|
|
143
|
+ std::min(rect_.top(), placeholderRect_.top())),
|
|
144
|
+ QPoint(std::max(rect_.right(), placeholderRect_.right()),
|
|
145
|
+ std::max(rect_.bottom(), placeholderRect_.bottom())));
|
|
146
|
+
|
|
147
|
+ double xScale = 0.9 * s.width() / br.right();
|
|
148
|
+ double yScale = 0.9 * s.height() / br.bottom();
|
141
|
149
|
auto scale = std::min(xScale, yScale);
|
142
|
150
|
|
143
|
151
|
QPainter painter(this);
|
144
|
152
|
painter.fillRect(rect(), Qt::white);
|
145
|
153
|
painter.scale(scale, scale);
|
|
154
|
+ painter.save(); // push before translating
|
|
155
|
+ painter.translate(rect_.topLeft());
|
146
|
156
|
|
147
|
157
|
QStyleOptionGraphicsItem ogi;
|
148
|
158
|
ogi.exposedRect = br;
|
149
|
159
|
bitmapItem_->paint(&painter, &ogi, this);
|
150
|
160
|
|
|
161
|
+ painter.restore(); // undo translating.
|
151
|
162
|
double scaledLineWidth = 4 / scale;
|
|
163
|
+ double scaledLineWidthHalf = scaledLineWidth / 2;
|
152
|
164
|
painter.setPen(QPen(Qt::black, scaledLineWidth));
|
153
|
|
- scaledLineWidth /= 2;
|
154
|
|
- painter.drawRect(br.adjusted(scaledLineWidth, scaledLineWidth,
|
155
|
|
- -scaledLineWidth, -scaledLineWidth));
|
|
165
|
+ painter.drawRect(QRectF(br).adjusted(scaledLineWidthHalf,
|
|
166
|
+ scaledLineWidthHalf,
|
|
167
|
+ -scaledLineWidthHalf,
|
|
168
|
+ -scaledLineWidthHalf));
|
|
169
|
+ painter.setPen(QPen(Qt::red, scaledLineWidth));
|
|
170
|
+ painter.drawRect(QRectF(placeholderRect_).adjusted(scaledLineWidthHalf,
|
|
171
|
+ scaledLineWidthHalf,
|
|
172
|
+ -scaledLineWidthHalf,
|
|
173
|
+ -scaledLineWidthHalf));
|
|
174
|
+ painter.setPen(QPen(Qt::blue, scaledLineWidth));
|
|
175
|
+ painter.drawRect(QRectF(rect_).adjusted(scaledLineWidthHalf,
|
|
176
|
+ scaledLineWidthHalf,
|
|
177
|
+ -scaledLineWidthHalf,
|
|
178
|
+ -scaledLineWidthHalf));
|
156
|
179
|
}
|
157
|
180
|
|
158
|
181
|
|
src/ftinspect/glyphcomponents/glyphbitmap.hpp
... |
... |
@@ -48,8 +48,8 @@ class GlyphBitmapWidget |
48
|
48
|
public:
|
49
|
49
|
GlyphBitmapWidget(QWidget* parent);
|
50
|
50
|
~GlyphBitmapWidget() override;
|
51
|
|
-
|
52
|
|
- void updateImage(QImage* image, QRect rect);
|
|
51
|
+
|
|
52
|
+ void updateImage(QImage* image, QRect rect, QRect placeholderRect = {});
|
53
|
53
|
void releaseImage();
|
54
|
54
|
|
55
|
55
|
signals:
|
... |
... |
@@ -62,6 +62,8 @@ protected: |
62
|
62
|
|
63
|
63
|
private:
|
64
|
64
|
GlyphBitmap* bitmapItem_ = NULL;
|
|
65
|
+ QRect rect_ = {};
|
|
66
|
+ QRect placeholderRect_ = {};
|
65
|
67
|
};
|
66
|
68
|
|
67
|
69
|
|
src/ftinspect/panels/glyphdetails.cpp
... |
... |
@@ -28,6 +28,7 @@ GlyphDetails::~GlyphDetails() |
28
|
28
|
void
|
29
|
29
|
GlyphDetails::updateGlyph(GlyphCacheEntry& ctxt, int charMapIndex)
|
30
|
30
|
{
|
|
31
|
+ auto metrics = engine_->currentFontMetrics();
|
31
|
32
|
auto& cMaps = engine_->currentFontCharMaps();
|
32
|
33
|
|
33
|
34
|
glyphIndex_ = ctxt.glyphIndex;
|
... |
... |
@@ -49,10 +50,16 @@ GlyphDetails::updateGlyph(GlyphCacheEntry& ctxt, int charMapIndex) |
49
|
50
|
if (glyphName.isEmpty())
|
50
|
51
|
glyphName = "(none)";
|
51
|
52
|
glyphNameLabel_->setText(glyphName);
|
52
|
|
-
|
|
53
|
+
|
53
|
54
|
auto rect = ctxt.basePosition.translated(-(ctxt.penPos.x()),
|
54
|
55
|
-(ctxt.penPos.y()));
|
55
|
|
- bitmapWidget_->updateImage(ctxt.image, rect);
|
|
56
|
+ auto drawRect = rect;
|
|
57
|
+ drawRect.moveTop(drawRect.top() + (metrics.ascender >> 6));
|
|
58
|
+ if (!ctxt.advance.x)
|
|
59
|
+ drawRect.moveLeft(drawRect.left() + ctxt.nonSpacingPlaceholder);
|
|
60
|
+ bitmapWidget_->updateImage(
|
|
61
|
+ ctxt.image, drawRect,
|
|
62
|
+ QRect(0, 0, metrics.y_ppem, metrics.y_ppem));
|
56
|
63
|
|
57
|
64
|
// load glyphs in all units
|
58
|
65
|
dpi_ = engine_->dpi();
|
|