Project

General

Profile

Bug #7810

measureText() not accurate

Added by Michał Błaszak about 1 month ago. Updated about 1 month ago.

Status:
New
Priority:
Normal
Assignee:
-
Target version:
-
Start date:
10/30/2020
Due date:
% Done:

0%

Estimated time:

Description

I'm trying to implement a canvas-based text editor. I need to place the caret pointer in an exactly correct place.
The idea is to calculate the length of the text drawn on the canvas, draw the vertical like in that place and then draw the rest of the text.
measureText() seemed to be perfect for this task.

The following piece of code draws the entire text and puts the caret sign at the end of the text:

void paintEvent(Wt::WPaintDevice* paintDevice) {
Wt::WPainter painter(paintDevice);
double font_size = painter.font().sizeLength().value();

painter.drawText(0, 0, 400, 300, Wt::AlignmentFlag::Left | Wt::AlignmentFlag::Top, txt_);

// Draw a caret
double x = painter.device()->measureText(txt_).width();
painter.drawLine(x, 0, x, font_size);
}

The issue is that the more characters the string contains the less accurate is the width calculated by measureText().
The attached image demonstrates the situation with different text length.


Files

measureText.png (15.8 KB) measureText.png Michał Błaszak, 10/30/2020 11:01 PM
#1

Updated by Michał Błaszak about 1 month ago

I found this in ServerSideFontMethics.c (look at REL_ERROR = 1.02; what is it for? When I divide the width returned by measureText() by 1.02 I get the perfect result!):

WTextItem
ServerSideFontMetrics::measureText(const WFont& font,
const WString& text, double maxWidth,
bool wordWrap)
{
#ifdef WT_HAS_WPDFIMAGE
painter_->setFont(font);
WTextItem t = painter_->device()->measureText(text, maxWidth, wordWrap);
const double REL_ERROR = 1.02;
return WTextItem(t.text(), t.width() * REL_ERROR,
t.nextWidth() > 0 ? t.nextWidth() * REL_ERROR : t.nextWidth());
#else
throw WException("ServerSideFontMetrics not available");
#endif // WT_HAS_WPDFIMAGE
}

Also available in: Atom PDF