aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--cocoa/PlatCocoa.h10
-rw-r--r--cocoa/PlatCocoa.mm98
-rwxr-xr-xgtk/PlatGTK.cxx88
-rw-r--r--qt/ScintillaEditBase/PlatQt.cpp81
-rw-r--r--qt/ScintillaEditBase/PlatQt.h11
-rw-r--r--src/Platform.h7
-rw-r--r--win32/PlatWin.cxx293
7 files changed, 554 insertions, 34 deletions
diff --git a/cocoa/PlatCocoa.h b/cocoa/PlatCocoa.h
index 1ddb203c7..b918e5ed0 100644
--- a/cocoa/PlatCocoa.h
+++ b/cocoa/PlatCocoa.h
@@ -104,6 +104,7 @@ public:
void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) override;
void Copy(PRectangle rc, Scintilla::Point from, Surface &surfaceSource) override;
std::unique_ptr<IScreenLineLayout> Layout(const IScreenLine *screenLine) override;
+
void DrawTextNoClip(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore,
ColourDesired back) override;
void DrawTextClipped(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore,
@@ -111,6 +112,15 @@ public:
void DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) override;
void MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) override;
XYPOSITION WidthText(const Font *font_, std::string_view text) override;
+
+ void DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore,
+ ColourDesired back) override;
+ void DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore,
+ ColourDesired back) override;
+ void DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) override;
+ void MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) override;
+ XYPOSITION WidthTextUTF8(const Font *font_, std::string_view text) override;
+
XYPOSITION Ascent(const Font *font_) override;
XYPOSITION Descent(const Font *font_) override;
XYPOSITION InternalLeading(const Font *font_) override;
diff --git a/cocoa/PlatCocoa.mm b/cocoa/PlatCocoa.mm
index 2e3ab2d57..f84a335aa 100644
--- a/cocoa/PlatCocoa.mm
+++ b/cocoa/PlatCocoa.mm
@@ -1227,6 +1227,104 @@ XYPOSITION SurfaceImpl::WidthText(const Font *font_, std::string_view text) {
return static_cast<XYPOSITION>(textLayout->MeasureStringWidth());
}
+//--------------------------------------------------------------------------------------------------
+
+void SurfaceImpl::DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+ ColourDesired fore, ColourDesired back) {
+ FillRectangle(rc, back);
+ DrawTextTransparent(rc, font_, ybase, text, fore);
+}
+
+//--------------------------------------------------------------------------------------------------
+
+void SurfaceImpl::DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+ ColourDesired fore, ColourDesired back) {
+ CGContextSaveGState(gc);
+ CGContextClipToRect(gc, PRectangleToCGRect(rc));
+ DrawTextNoClip(rc, font_, ybase, text, fore, back);
+ CGContextRestoreGState(gc);
+}
+
+//--------------------------------------------------------------------------------------------------
+
+void SurfaceImpl::DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+ ColourDesired fore) {
+ QuartzTextStyle *style = TextStyleFromFont(font_);
+ if (!style) {
+ return;
+ }
+ const CFStringEncoding encoding = kCFStringEncodingUTF8;
+ ColourDesired colour(fore.AsInteger());
+ CGColorRef color = CGColorCreateGenericRGB(colour.GetRed()/255.0, colour.GetGreen()/255.0, colour.GetBlue()/255.0, 1.0);
+
+ style->setCTStyleColour(color);
+
+ CGColorRelease(color);
+
+ textLayout->setText(text, encoding, style);
+ textLayout->draw(gc, rc.left, ybase);
+}
+
+//--------------------------------------------------------------------------------------------------
+
+void SurfaceImpl::MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) {
+ const QuartzTextStyle *style = TextStyleFromFont(font_);
+ if (!style) {
+ return;
+ }
+ const CFStringEncoding encoding = kCFStringEncodingUTF8;
+ const CFStringEncoding encodingUsed =
+ textLayout->setText(text, encoding, style);
+
+ CTLineRef mLine = textLayout->getCTLine();
+ assert(mLine);
+
+ if (encodingUsed != encoding) {
+ // Switched to MacRoman to make work so treat as single byte encoding.
+ for (int i=0; i<text.length(); i++) {
+ CGFloat xPosition = CTLineGetOffsetForStringIndex(mLine, i+1, nullptr);
+ positions[i] = static_cast<XYPOSITION>(xPosition);
+ }
+ return;
+ }
+
+ // Map the widths given for UTF-16 characters back onto the UTF-8 input string
+ CFIndex fit = textLayout->getStringLength();
+ int ui=0;
+ int i=0;
+ std::vector<CGFloat> linePositions(fit);
+ GetPositions(mLine, linePositions);
+ while (ui<fit) {
+ const unsigned char uch = text[i];
+ const unsigned int byteCount = UTF8BytesOfLead[uch];
+ const int codeUnits = UTF16LengthFromUTF8ByteCount(byteCount);
+ const CGFloat xPosition = linePositions[ui];
+ for (unsigned int bytePos=0; (bytePos<byteCount) && (i<text.length()); bytePos++) {
+ positions[i++] = static_cast<XYPOSITION>(xPosition);
+ }
+ ui += codeUnits;
+ }
+ XYPOSITION lastPos = 0.0f;
+ if (i > 0)
+ lastPos = positions[i-1];
+ while (i<text.length()) {
+ positions[i++] = lastPos;
+ }
+}
+
+XYPOSITION SurfaceImpl::WidthTextUTF8(const Font *font_, std::string_view text) {
+ const QuartzTextStyle *style = TextStyleFromFont(font_);
+ if (!style) {
+ return 1;
+ }
+ textLayout->setText(text, kCFStringEncodingUTF8, style);
+
+ return static_cast<XYPOSITION>(textLayout->MeasureStringWidth());
+}
+
+//--------------------------------------------------------------------------------------------------
+
+
// This string contains a good range of characters to test for size.
const char sizeString[] = "`~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890"
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
diff --git a/gtk/PlatGTK.cxx b/gtk/PlatGTK.cxx
index 3f0918886..b9c049f1d 100755
--- a/gtk/PlatGTK.cxx
+++ b/gtk/PlatGTK.cxx
@@ -180,6 +180,14 @@ public:
void DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) override;
void MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) override;
XYPOSITION WidthText(const Font *font_, std::string_view text) override;
+
+ void DrawTextBaseUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore);
+ void DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) override;
+ void DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) override;
+ void DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) override;
+ void MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) override;
+ XYPOSITION WidthTextUTF8(const Font *font_, std::string_view text) override;
+
XYPOSITION Ascent(const Font *font_) override;
XYPOSITION Descent(const Font *font_) override;
XYPOSITION InternalLeading(const Font *font_) override;
@@ -914,6 +922,86 @@ XYPOSITION SurfaceImpl::WidthText(const Font *font_, std::string_view text) {
return 1;
}
+void SurfaceImpl::DrawTextBaseUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+ ColourDesired fore) {
+ PenColour(fore);
+ if (context) {
+ const XYPOSITION xText = rc.left;
+ if (PFont(font_)->pfd) {
+ pango_layout_set_text(layout, text.data(), text.length());
+ pango_layout_set_font_description(layout, PFont(font_)->pfd);
+ pango_cairo_update_layout(context, layout);
+ PangoLayoutLine *pll = pango_layout_get_line_readonly(layout, 0);
+ cairo_move_to(context, xText, ybase);
+ pango_cairo_show_layout_line(context, pll);
+ }
+ }
+}
+
+void SurfaceImpl::DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+ ColourDesired fore, ColourDesired back) {
+ FillRectangle(rc, back);
+ DrawTextBaseUTF8(rc, font_, ybase, text, fore);
+}
+
+// On GTK+, exactly same as DrawTextNoClip
+void SurfaceImpl::DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+ ColourDesired fore, ColourDesired back) {
+ FillRectangle(rc, back);
+ DrawTextBaseUTF8(rc, font_, ybase, text, fore);
+}
+
+void SurfaceImpl::DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+ ColourDesired fore) {
+ // Avoid drawing spaces in transparent mode
+ for (size_t i = 0; i < text.length(); i++) {
+ if (text[i] != ' ') {
+ DrawTextBaseUTF8(rc, font_, ybase, text, fore);
+ return;
+ }
+ }
+}
+
+void SurfaceImpl::MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) {
+ if (PFont(font_)->pfd) {
+ pango_layout_set_font_description(layout, PFont(font_)->pfd);
+ // Simple and direct as UTF-8 is native Pango encoding
+ int i = 0;
+ pango_layout_set_text(layout, text.data(), text.length());
+ ClusterIterator iti(layout, text.length());
+ while (!iti.finished) {
+ iti.Next();
+ const int places = iti.curIndex - i;
+ while (i < iti.curIndex) {
+ // Evenly distribute space among bytes of this cluster.
+ // Would be better to find number of characters and then
+ // divide evenly between characters with each byte of a character
+ // being at the same position.
+ positions[i] = iti.position - (iti.curIndex - 1 - i) * iti.distance / places;
+ i++;
+ }
+ }
+ PLATFORM_ASSERT(static_cast<size_t>(i) == text.length());
+ } else {
+ // No font so return an ascending range of values
+ for (size_t i = 0; i < text.length(); i++) {
+ positions[i] = i + 1;
+ }
+ }
+}
+
+XYPOSITION SurfaceImpl::WidthTextUTF8(const Font *font_, std::string_view text) {
+ if (PFont(font_)->pfd) {
+ pango_layout_set_font_description(layout, PFont(font_)->pfd);
+ pango_layout_set_text(layout, text.data(), text.length());
+ PangoLayoutLine *pangoLine = pango_layout_get_line_readonly(layout, 0);
+ PangoRectangle pos{};
+ pango_layout_line_get_extents(pangoLine, nullptr, &pos);
+ return floatFromPangoUnits(pos.width);
+ }
+ return 1;
+}
+
// Ascent and descent determined by Pango font metrics.
XYPOSITION SurfaceImpl::Ascent(const Font *font_) {
diff --git a/qt/ScintillaEditBase/PlatQt.cpp b/qt/ScintillaEditBase/PlatQt.cpp
index 6a26d47c4..a1adf0a0d 100644
--- a/qt/ScintillaEditBase/PlatQt.cpp
+++ b/qt/ScintillaEditBase/PlatQt.cpp
@@ -557,6 +557,87 @@ XYPOSITION SurfaceImpl::WidthText(const Font *font, std::string_view text)
return metrics.width(su);
}
+void SurfaceImpl::DrawTextNoClipUTF8(PRectangle rc,
+ const Font *font,
+ XYPOSITION ybase,
+ std::string_view text,
+ ColourDesired fore,
+ ColourDesired back)
+{
+ SetFont(font);
+ PenColour(fore);
+
+ GetPainter()->setBackground(QColorFromCA(back));
+ GetPainter()->setBackgroundMode(Qt::OpaqueMode);
+ QString su = QString::fromUtf8(text.data(), static_cast<int>(text.length()));
+ GetPainter()->drawText(QPointF(rc.left, ybase), su);
+}
+
+void SurfaceImpl::DrawTextClippedUTF8(PRectangle rc,
+ const Font *font,
+ XYPOSITION ybase,
+ std::string_view text,
+ ColourDesired fore,
+ ColourDesired back)
+{
+ SetClip(rc);
+ DrawTextNoClip(rc, font, ybase, text, fore, back);
+ PopClip();
+}
+
+void SurfaceImpl::DrawTextTransparentUTF8(PRectangle rc,
+ const Font *font,
+ XYPOSITION ybase,
+ std::string_view text,
+ ColourDesired fore)
+{
+ SetFont(font);
+ PenColour(fore);
+
+ GetPainter()->setBackgroundMode(Qt::TransparentMode);
+ QString su = QString::fromUtf8(text.data(), static_cast<int>(text.length()));
+ GetPainter()->drawText(QPointF(rc.left, ybase), su);
+}
+
+void SurfaceImpl::MeasureWidthsUTF8(const Font *font,
+ std::string_view text,
+ XYPOSITION *positions)
+{
+ if (!font)
+ return;
+ QString su = QString::fromUtf8(text.data(), static_cast<int>(text.length()));
+ QTextLayout tlay(su, *FontPointer(font), GetPaintDevice());
+ tlay.beginLayout();
+ QTextLine tl = tlay.createLine();
+ tlay.endLayout();
+ int fit = su.size();
+ int ui=0;
+ size_t i=0;
+ while (ui<fit) {
+ const unsigned char uch = text[i];
+ const unsigned int byteCount = UTF8BytesOfLead[uch];
+ const int codeUnits = UTF16LengthFromUTF8ByteCount(byteCount);
+ qreal xPosition = tl.cursorToX(ui+codeUnits);
+ for (size_t bytePos=0; (bytePos<byteCount) && (i<text.length()); bytePos++) {
+ positions[i++] = xPosition;
+ }
+ ui += codeUnits;
+ }
+ XYPOSITION lastPos = 0;
+ if (i > 0)
+ lastPos = positions[i-1];
+ while (i<text.length()) {
+ positions[i++] = lastPos;
+ }
+}
+
+XYPOSITION SurfaceImpl::WidthTextUTF8(const Font *font, std::string_view text)
+{
+ QFontMetricsF metrics(*FontPointer(font), device);
+ QString su = QString::fromUtf8(text.data(), static_cast<int>(text.length()));
+ return metrics.width(su);
+}
+
XYPOSITION SurfaceImpl::Ascent(const Font *font)
{
QFontMetricsF metrics(*FontPointer(font), device);
diff --git a/qt/ScintillaEditBase/PlatQt.h b/qt/ScintillaEditBase/PlatQt.h
index c690e7697..a743a4be5 100644
--- a/qt/ScintillaEditBase/PlatQt.h
+++ b/qt/ScintillaEditBase/PlatQt.h
@@ -126,6 +126,17 @@ public:
void MeasureWidths(const Font *font, std::string_view text,
XYPOSITION *positions) override;
XYPOSITION WidthText(const Font *font, std::string_view text) override;
+
+ void DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase,
+ std::string_view text, ColourDesired fore, ColourDesired back) override;
+ void DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase,
+ std::string_view text, ColourDesired fore, ColourDesired back) override;
+ void DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase,
+ std::string_view text, ColourDesired fore) override;
+ void MeasureWidthsUTF8(const Font *font_, std::string_view text,
+ XYPOSITION *positions) override;
+ XYPOSITION WidthTextUTF8(const Font *font_, std::string_view text) override;
+
XYPOSITION Ascent(const Font *font) override;
XYPOSITION Descent(const Font *font) override;
XYPOSITION InternalLeading(const Font *font) override;
diff --git a/src/Platform.h b/src/Platform.h
index 3333d3d4c..45c04abdc 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -208,6 +208,13 @@ public:
virtual void DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) = 0;
virtual void MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) = 0;
virtual XYPOSITION WidthText(const Font *font_, std::string_view text) = 0;
+
+ virtual void DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) = 0;
+ virtual void DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) = 0;
+ virtual void DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) = 0;
+ virtual void MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) = 0;
+ virtual XYPOSITION WidthTextUTF8(const Font *font_, std::string_view text) = 0;
+
virtual XYPOSITION Ascent(const Font *font_)=0;
virtual XYPOSITION Descent(const Font *font_)=0;
virtual XYPOSITION InternalLeading(const Font *font_)=0;
diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx
index 26a351871..3f93a96fd 100644
--- a/win32/PlatWin.cxx
+++ b/win32/PlatWin.cxx
@@ -506,6 +506,14 @@ public:
void DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) override;
void MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) override;
XYPOSITION WidthText(const Font *font_, std::string_view text) override;
+
+ void DrawTextCommonUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, UINT fuOptions);
+ void DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) override;
+ void DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) override;
+ void DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) override;
+ void MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) override;
+ XYPOSITION WidthTextUTF8(const Font *font_, std::string_view text) override;
+
XYPOSITION Ascent(const Font *font_) override;
XYPOSITION Descent(const Font *font_) override;
XYPOSITION InternalLeading(const Font *font_) override;
@@ -1003,23 +1011,11 @@ void SurfaceGDI::DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITIO
}
}
-XYPOSITION SurfaceGDI::WidthText(const Font *font_, std::string_view text) {
- SetFont(font_);
- SIZE sz={0,0};
- if (!unicodeMode) {
- ::GetTextExtentPoint32A(hdc, text.data(), std::min(static_cast<int>(text.length()), maxLenText), &sz);
- } else {
- const TextWide tbuf(text, unicodeMode, codePage);
- ::GetTextExtentPoint32W(hdc, tbuf.buffer, tbuf.tlen, &sz);
- }
- return static_cast<XYPOSITION>(sz.cx);
-}
-
void SurfaceGDI::MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) {
// Zero positions to avoid random behaviour on failure.
std::fill(positions, positions + text.length(), 0.0f);
SetFont(font_);
- SIZE sz={0,0};
+ SIZE sz = { 0,0 };
int fit = 0;
int i = 0;
const int len = static_cast<int>(text.length());
@@ -1037,7 +1033,7 @@ void SurfaceGDI::MeasureWidths(const Font *font_, std::string_view text, XYPOSIT
if (byteCount == 4) { // Non-BMP
ui++;
}
- for (unsigned int bytePos=0; (bytePos<byteCount) && (i<len); bytePos++) {
+ for (unsigned int bytePos = 0; (bytePos < byteCount) && (i < len); bytePos++) {
positions[i++] = static_cast<XYPOSITION>(poses.buffer[ui]);
}
}
@@ -1047,14 +1043,102 @@ void SurfaceGDI::MeasureWidths(const Font *font_, std::string_view text, XYPOSIT
// Eeek - a NULL DC or other foolishness could cause this.
return;
}
- while (i<fit) {
+ while (i < fit) {
positions[i] = static_cast<XYPOSITION>(poses.buffer[i]);
i++;
}
}
// If any positions not filled in then use the last position for them
const XYPOSITION lastPos = (fit > 0) ? positions[fit - 1] : 0.0f;
- std::fill(positions+i, positions + text.length(), lastPos);
+ std::fill(positions + i, positions + text.length(), lastPos);
+}
+
+XYPOSITION SurfaceGDI::WidthText(const Font *font_, std::string_view text) {
+ SetFont(font_);
+ SIZE sz = { 0,0 };
+ if (!unicodeMode) {
+ ::GetTextExtentPoint32A(hdc, text.data(), std::min(static_cast<int>(text.length()), maxLenText), &sz);
+ } else {
+ const TextWide tbuf(text, unicodeMode, codePage);
+ ::GetTextExtentPoint32W(hdc, tbuf.buffer, tbuf.tlen, &sz);
+ }
+ return static_cast<XYPOSITION>(sz.cx);
+}
+
+void SurfaceGDI::DrawTextCommonUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, UINT fuOptions) {
+ SetFont(font_);
+ const RECT rcw = RectFromPRectangle(rc);
+ const int x = static_cast<int>(rc.left);
+ const int yBaseInt = static_cast<int>(ybase);
+
+ const TextWide tbuf(text, true);
+ ::ExtTextOutW(hdc, x, yBaseInt, fuOptions, &rcw, tbuf.buffer, tbuf.tlen, nullptr);
+}
+
+void SurfaceGDI::DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+ ColourDesired fore, ColourDesired back) {
+ ::SetTextColor(hdc, fore.AsInteger());
+ ::SetBkColor(hdc, back.AsInteger());
+ DrawTextCommonUTF8(rc, font_, ybase, text, ETO_OPAQUE);
+}
+
+void SurfaceGDI::DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+ ColourDesired fore, ColourDesired back) {
+ ::SetTextColor(hdc, fore.AsInteger());
+ ::SetBkColor(hdc, back.AsInteger());
+ DrawTextCommonUTF8(rc, font_, ybase, text, ETO_OPAQUE | ETO_CLIPPED);
+}
+
+void SurfaceGDI::DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+ ColourDesired fore) {
+ // Avoid drawing spaces in transparent mode
+ for (const char ch : text) {
+ if (ch != ' ') {
+ ::SetTextColor(hdc, fore.AsInteger());
+ ::SetBkMode(hdc, TRANSPARENT);
+ DrawTextCommonUTF8(rc, font_, ybase, text, 0);
+ ::SetBkMode(hdc, OPAQUE);
+ return;
+ }
+ }
+}
+
+void SurfaceGDI::MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) {
+ // Zero positions to avoid random behaviour on failure.
+ std::fill(positions, positions + text.length(), 0.0f);
+ SetFont(font_);
+ SIZE sz = { 0,0 };
+ int fit = 0;
+ int i = 0;
+ const int len = static_cast<int>(text.length());
+ const TextWide tbuf(text, true);
+ TextPositionsI poses(tbuf.tlen);
+ if (!::GetTextExtentExPointW(hdc, tbuf.buffer, tbuf.tlen, maxWidthMeasure, &fit, poses.buffer, &sz)) {
+ // Failure
+ return;
+ }
+ // Map the widths given for UTF-16 characters back onto the UTF-8 input string
+ for (int ui = 0; ui < fit; ui++) {
+ const unsigned char uch = text[i];
+ const unsigned int byteCount = UTF8BytesOfLead[uch];
+ if (byteCount == 4) { // Non-BMP
+ ui++;
+ }
+ for (unsigned int bytePos = 0; (bytePos < byteCount) && (i < len); bytePos++) {
+ positions[i++] = static_cast<XYPOSITION>(poses.buffer[ui]);
+ }
+ }
+ // If any positions not filled in then use the last position for them
+ const XYPOSITION lastPos = (fit > 0) ? positions[fit - 1] : 0.0f;
+ std::fill(positions + i, positions + text.length(), lastPos);
+}
+
+XYPOSITION SurfaceGDI::WidthTextUTF8(const Font *font_, std::string_view text) {
+ SetFont(font_);
+ SIZE sz = { 0,0 };
+ const TextWide tbuf(text, true);
+ ::GetTextExtentPoint32W(hdc, tbuf.buffer, tbuf.tlen, &sz);
+ return static_cast<XYPOSITION>(sz.cx);
}
XYPOSITION SurfaceGDI::Ascent(const Font *font_) {
@@ -1208,6 +1292,14 @@ public:
void DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) override;
void MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) override;
XYPOSITION WidthText(const Font *font_, std::string_view text) override;
+
+ void DrawTextCommonUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, UINT fuOptions);
+ void DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) override;
+ void DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) override;
+ void DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) override;
+ void MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) override;
+ XYPOSITION WidthTextUTF8(const Font *font_, std::string_view text) override;
+
XYPOSITION Ascent(const Font *font_) override;
XYPOSITION Descent(const Font *font_) override;
XYPOSITION InternalLeading(const Font *font_) override;
@@ -2104,24 +2196,6 @@ void SurfaceD2D::DrawTextTransparent(PRectangle rc, const Font *font_, XYPOSITIO
}
}
-XYPOSITION SurfaceD2D::WidthText(const Font *font_, std::string_view text) {
- FLOAT width = 1.0;
- SetFont(font_);
- const TextWide tbuf(text, unicodeMode, codePageText);
- if (pIDWriteFactory && pTextFormat) {
- // Create a layout
- IDWriteTextLayout *pTextLayout = nullptr;
- const HRESULT hr = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, 1000.0, 1000.0, &pTextLayout);
- if (SUCCEEDED(hr) && pTextLayout) {
- DWRITE_TEXT_METRICS textMetrics;
- if (SUCCEEDED(pTextLayout->GetMetrics(&textMetrics)))
- width = textMetrics.widthIncludingTrailingWhitespace;
- ReleaseUnknown(pTextLayout);
- }
- }
- return width;
-}
-
void SurfaceD2D::MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) {
SetFont(font_);
if (!pIDWriteFactory || !pTextFormat) {
@@ -2203,6 +2277,157 @@ void SurfaceD2D::MeasureWidths(const Font *font_, std::string_view text, XYPOSIT
}
}
+XYPOSITION SurfaceD2D::WidthText(const Font *font_, std::string_view text) {
+ FLOAT width = 1.0;
+ SetFont(font_);
+ const TextWide tbuf(text, unicodeMode, codePageText);
+ if (pIDWriteFactory && pTextFormat) {
+ // Create a layout
+ IDWriteTextLayout *pTextLayout = nullptr;
+ const HRESULT hr = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, 1000.0, 1000.0, &pTextLayout);
+ if (SUCCEEDED(hr) && pTextLayout) {
+ DWRITE_TEXT_METRICS textMetrics;
+ if (SUCCEEDED(pTextLayout->GetMetrics(&textMetrics)))
+ width = textMetrics.widthIncludingTrailingWhitespace;
+ ReleaseUnknown(pTextLayout);
+ }
+ }
+ return width;
+}
+
+void SurfaceD2D::DrawTextCommonUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, UINT fuOptions) {
+ SetFont(font_);
+
+ // Use Unicode calls
+ const TextWide tbuf(text, true);
+ if (pRenderTarget && pTextFormat && pBrush) {
+ if (fuOptions & ETO_CLIPPED) {
+ D2D1_RECT_F rcClip = { rc.left, rc.top, rc.right, rc.bottom };
+ pRenderTarget->PushAxisAlignedClip(rcClip, D2D1_ANTIALIAS_MODE_ALIASED);
+ }
+
+ // Explicitly creating a text layout appears a little faster
+ IDWriteTextLayout *pTextLayout = nullptr;
+ const HRESULT hr = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat,
+ rc.Width(), rc.Height(), &pTextLayout);
+ if (SUCCEEDED(hr)) {
+ D2D1_POINT_2F origin = {rc.left, ybase-yAscent};
+ pRenderTarget->DrawTextLayout(origin, pTextLayout, pBrush, d2dDrawTextOptions);
+ ReleaseUnknown(pTextLayout);
+ }
+
+ if (fuOptions & ETO_CLIPPED) {
+ pRenderTarget->PopAxisAlignedClip();
+ }
+ }
+}
+
+void SurfaceD2D::DrawTextNoClipUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+ ColourDesired fore, ColourDesired back) {
+ if (pRenderTarget) {
+ FillRectangle(rc, back);
+ D2DPenColour(fore);
+ DrawTextCommonUTF8(rc, font_, ybase, text, ETO_OPAQUE);
+ }
+}
+
+void SurfaceD2D::DrawTextClippedUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+ ColourDesired fore, ColourDesired back) {
+ if (pRenderTarget) {
+ FillRectangle(rc, back);
+ D2DPenColour(fore);
+ DrawTextCommonUTF8(rc, font_, ybase, text, ETO_OPAQUE | ETO_CLIPPED);
+ }
+}
+
+void SurfaceD2D::DrawTextTransparentUTF8(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text,
+ ColourDesired fore) {
+ // Avoid drawing spaces in transparent mode
+ for (const char ch : text) {
+ if (ch != ' ') {
+ if (pRenderTarget) {
+ D2DPenColour(fore);
+ DrawTextCommonUTF8(rc, font_, ybase, text, 0);
+ }
+ return;
+ }
+ }
+}
+
+void SurfaceD2D::MeasureWidthsUTF8(const Font *font_, std::string_view text, XYPOSITION *positions) {
+ SetFont(font_);
+ if (!pIDWriteFactory || !pTextFormat) {
+ // SetFont failed or no access to DirectWrite so give up.
+ return;
+ }
+ const TextWide tbuf(text, true);
+ TextPositions poses(tbuf.tlen);
+ // Initialize poses for safety.
+ std::fill(poses.buffer, poses.buffer + tbuf.tlen, 0.0f);
+ // Create a layout
+ IDWriteTextLayout *pTextLayout = nullptr;
+ const HRESULT hrCreate = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, 10000.0, 1000.0, &pTextLayout);
+ if (!SUCCEEDED(hrCreate)) {
+ return;
+ }
+ constexpr int clusters = stackBufferLength;
+ DWRITE_CLUSTER_METRICS clusterMetrics[clusters];
+ UINT32 count = 0;
+ const HRESULT hrGetCluster = pTextLayout->GetClusterMetrics(clusterMetrics, clusters, &count);
+ ReleaseUnknown(pTextLayout);
+ if (!SUCCEEDED(hrGetCluster)) {
+ return;
+ }
+ // A cluster may be more than one WCHAR, such as for "ffi" which is a ligature in the Candara font
+ FLOAT position = 0.0f;
+ size_t ti = 0;
+ for (size_t ci = 0; ci < count; ci++) {
+ for (size_t inCluster = 0; inCluster < clusterMetrics[ci].length; inCluster++) {
+ poses.buffer[ti++] = position + clusterMetrics[ci].width * (inCluster + 1) / clusterMetrics[ci].length;
+ }
+ position += clusterMetrics[ci].width;
+ }
+ PLATFORM_ASSERT(ti == static_cast<size_t>(tbuf.tlen));
+ // Map the widths given for UTF-16 characters back onto the UTF-8 input string
+ int ui = 0;
+ size_t i = 0;
+ while (ui < tbuf.tlen) {
+ const unsigned char uch = text[i];
+ const unsigned int byteCount = UTF8BytesOfLead[uch];
+ if (byteCount == 4) { // Non-BMP
+ ui++;
+ }
+ for (unsigned int bytePos = 0; (bytePos < byteCount) && (i < text.length()); bytePos++) {
+ positions[i++] = poses.buffer[ui];
+ }
+ ui++;
+ }
+ XYPOSITION lastPos = 0.0f;
+ if (i > 0)
+ lastPos = positions[i - 1];
+ while (i < text.length()) {
+ positions[i++] = lastPos;
+ }
+}
+
+XYPOSITION SurfaceD2D::WidthTextUTF8(const Font * font_, std::string_view text) {
+ FLOAT width = 1.0;
+ SetFont(font_);
+ const TextWide tbuf(text, true);
+ if (pIDWriteFactory && pTextFormat) {
+ // Create a layout
+ IDWriteTextLayout *pTextLayout = nullptr;
+ const HRESULT hr = pIDWriteFactory->CreateTextLayout(tbuf.buffer, tbuf.tlen, pTextFormat, 1000.0, 1000.0, &pTextLayout);
+ if (SUCCEEDED(hr)) {
+ DWRITE_TEXT_METRICS textMetrics;
+ if (SUCCEEDED(pTextLayout->GetMetrics(&textMetrics)))
+ width = textMetrics.widthIncludingTrailingWhitespace;
+ ReleaseUnknown(pTextLayout);
+ }
+ }
+ return width;
+}
+
XYPOSITION SurfaceD2D::Ascent(const Font *font_) {
SetFont(font_);
return std::ceil(yAscent);