diff options
Diffstat (limited to 'gtk/PlatGTK.cxx')
-rwxr-xr-x | gtk/PlatGTK.cxx | 305 |
1 files changed, 140 insertions, 165 deletions
diff --git a/gtk/PlatGTK.cxx b/gtk/PlatGTK.cxx index b9b9ab029..5471a7289 100755 --- a/gtk/PlatGTK.cxx +++ b/gtk/PlatGTK.cxx @@ -71,9 +71,9 @@ GtkWidget *PWidget(WindowID wid) noexcept { enum encodingType { singleByte, UTF8, dbcs }; // Holds a PangoFontDescription*. -class FontHandle { +class FontHandle : public Font { public: - PangoFontDescription *pfd; + PangoFontDescription *pfd = nullptr; int characterSet; FontHandle() noexcept : pfd(nullptr), characterSet(-1) { } @@ -81,6 +81,17 @@ public: pfd = pfd_; characterSet = characterSet_; } + FontHandle(const FontParameters &fp) { + pfd = pango_font_description_new(); + if (pfd) { + pango_font_description_set_family(pfd, + (fp.faceName[0] == '!') ? fp.faceName + 1 : fp.faceName); + pango_font_description_set_size(pfd, pangoUnitsFromDouble(fp.size)); + pango_font_description_set_weight(pfd, static_cast<PangoWeight>(fp.weight)); + pango_font_description_set_style(pfd, fp.italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); + } + characterSet = fp.characterSet; + } // Deleted so FontHandle objects can not be copied. FontHandle(const FontHandle &) = delete; FontHandle(FontHandle &&) = delete; @@ -91,45 +102,19 @@ public: pango_font_description_free(pfd); pfd = nullptr; } - static FontHandle *CreateNewFont(const FontParameters &fp); }; -FontHandle *FontHandle::CreateNewFont(const FontParameters &fp) { - PangoFontDescription *pfd = pango_font_description_new(); - if (pfd) { - pango_font_description_set_family(pfd, - (fp.faceName[0] == '!') ? fp.faceName+1 : fp.faceName); - pango_font_description_set_size(pfd, pangoUnitsFromDouble(fp.size)); - pango_font_description_set_weight(pfd, static_cast<PangoWeight>(fp.weight)); - pango_font_description_set_style(pfd, fp.italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); - return new FontHandle(pfd, fp.characterSet); - } - - return nullptr; -} - // X has a 16 bit coordinate space, so stop drawing here to avoid wrapping constexpr int maxCoordinate = 32000; -FontHandle *PFont(const Font &f) noexcept { - return static_cast<FontHandle *>(f.GetID()); +const FontHandle *PFont(const Font *f) noexcept { + return dynamic_cast<const FontHandle *>(f); } } -Font::Font() noexcept : fid(nullptr) {} - -Font::~Font() {} - -void Font::Create(const FontParameters &fp) { - Release(); - fid = FontHandle::CreateNewFont(fp); -} - -void Font::Release() { - if (fid) - delete static_cast<FontHandle *>(fid); - fid = nullptr; +std::shared_ptr<Font> Font::Allocate(const FontParameters &fp) { + return std::make_shared<FontHandle>(fp); } // Required on OS X @@ -184,17 +169,17 @@ public: std::unique_ptr<IScreenLineLayout> Layout(const IScreenLine *screenLine) override; - void DrawTextBase(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, ColourDesired fore); - void DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) override; - void DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) override; - void DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) override; - void MeasureWidths(Font &font_, std::string_view text, XYPOSITION *positions) override; - XYPOSITION WidthText(Font &font_, std::string_view text) override; - XYPOSITION Ascent(Font &font_) override; - XYPOSITION Descent(Font &font_) override; - XYPOSITION InternalLeading(Font &font_) override; - XYPOSITION Height(Font &font_) override; - XYPOSITION AverageCharWidth(Font &font_) override; + void DrawTextBase(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore); + 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, ColourDesired back) override; + 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; + XYPOSITION Ascent(const Font *font_) override; + XYPOSITION Descent(const Font *font_) override; + XYPOSITION InternalLeading(const Font *font_) override; + XYPOSITION Height(const Font *font_) override; + XYPOSITION AverageCharWidth(const Font *font_) override; void SetClip(PRectangle rc) override; void FlushCachedState() override; @@ -684,7 +669,7 @@ size_t MultiByteLenFromIconv(const Converter &conv, const char *s, size_t len) n } -void SurfaceImpl::DrawTextBase(PRectangle rc, const Font &font_, XYPOSITION ybase, std::string_view text, +void SurfaceImpl::DrawTextBase(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore) { PenColour(fore); if (context) { @@ -710,20 +695,20 @@ void SurfaceImpl::DrawTextBase(PRectangle rc, const Font &font_, XYPOSITION ybas } } -void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, XYPOSITION ybase, std::string_view text, +void SurfaceImpl::DrawTextNoClip(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) { FillRectangle(rc, back); DrawTextBase(rc, font_, ybase, text, fore); } // On GTK+, exactly same as DrawTextNoClip -void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, XYPOSITION ybase, std::string_view text, +void SurfaceImpl::DrawTextClipped(PRectangle rc, const Font *font_, XYPOSITION ybase, std::string_view text, ColourDesired fore, ColourDesired back) { FillRectangle(rc, back); DrawTextBase(rc, font_, ybase, text, fore); } -void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, XYPOSITION ybase, std::string_view text, +void SurfaceImpl::DrawTextTransparent(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++) { @@ -774,102 +759,100 @@ public: } }; -void SurfaceImpl::MeasureWidths(Font &font_, std::string_view text, XYPOSITION *positions) { - if (font_.GetID()) { - if (PFont(font_)->pfd) { - pango_layout_set_font_description(layout, PFont(font_)->pfd); - if (et == UTF8) { - // 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 { - int positionsCalculated = 0; - if (et == dbcs) { - SetConverter(PFont(font_)->characterSet); - std::string utfForm = UTF8FromIconv(conv, text); - if (!utfForm.empty()) { - // Convert to UTF-8 so can ask Pango for widths, then - // Loop through UTF-8 and DBCS forms, taking account of different - // character byte lengths. - Converter convMeasure("UCS-2", CharacterSetID(characterSet), false); - pango_layout_set_text(layout, utfForm.c_str(), strlen(utfForm.c_str())); - int i = 0; - int clusterStart = 0; - ClusterIterator iti(layout, strlen(utfForm.c_str())); - while (!iti.finished) { - iti.Next(); - const int clusterEnd = iti.curIndex; - const int places = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart); - int place = 1; - while (clusterStart < clusterEnd) { - size_t lenChar = MultiByteLenFromIconv(convMeasure, text.data()+i, text.length()-i); - while (lenChar--) { - positions[i++] = iti.position - (places - place) * iti.distance / places; - positionsCalculated++; - } - clusterStart += UTF8BytesOfLead[static_cast<unsigned char>(utfForm[clusterStart])]; - place++; - } - } - PLATFORM_ASSERT(static_cast<size_t>(i) == text.length()); - } +void SurfaceImpl::MeasureWidths(const Font *font_, std::string_view text, XYPOSITION *positions) { + if (PFont(font_)->pfd) { + pango_layout_set_font_description(layout, PFont(font_)->pfd); + if (et == UTF8) { + // 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++; } - if (positionsCalculated < 1) { - const size_t lenPositions = text.length(); - // Either 8-bit or DBCS conversion failed so treat as 8-bit. - SetConverter(PFont(font_)->characterSet); - const bool rtlCheck = PFont(font_)->characterSet == SC_CHARSET_HEBREW || - PFont(font_)->characterSet == SC_CHARSET_ARABIC; - std::string utfForm = UTF8FromIconv(conv, text); - if (utfForm.empty()) { - utfForm = UTF8FromLatin1(text); - } - pango_layout_set_text(layout, utfForm.c_str(), utfForm.length()); - size_t i = 0; + } + PLATFORM_ASSERT(static_cast<size_t>(i) == text.length()); + } else { + int positionsCalculated = 0; + if (et == dbcs) { + SetConverter(PFont(font_)->characterSet); + std::string utfForm = UTF8FromIconv(conv, text); + if (!utfForm.empty()) { + // Convert to UTF-8 so can ask Pango for widths, then + // Loop through UTF-8 and DBCS forms, taking account of different + // character byte lengths. + Converter convMeasure("UCS-2", CharacterSetID(characterSet), false); + pango_layout_set_text(layout, utfForm.c_str(), strlen(utfForm.c_str())); + int i = 0; int clusterStart = 0; - // Each 8-bit input character may take 1 or 2 bytes in UTF-8 - // and groups of up to 3 may be represented as ligatures. - ClusterIterator iti(layout, utfForm.length()); + ClusterIterator iti(layout, strlen(utfForm.c_str())); while (!iti.finished) { iti.Next(); const int clusterEnd = iti.curIndex; - const int ligatureLength = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart); - if (rtlCheck && ((clusterEnd <= clusterStart) || (ligatureLength == 0) || (ligatureLength > 3))) { - // Something has gone wrong: exit quickly but pretend all the characters are equally spaced: - int widthLayout = 0; - pango_layout_get_size(layout, &widthLayout, nullptr); - const XYPOSITION widthTotal = floatFromPangoUnits(widthLayout); - for (size_t bytePos=0; bytePos<lenPositions; bytePos++) { - positions[bytePos] = widthTotal / lenPositions * (bytePos + 1); + const int places = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart); + int place = 1; + while (clusterStart < clusterEnd) { + size_t lenChar = MultiByteLenFromIconv(convMeasure, text.data()+i, text.length()-i); + while (lenChar--) { + positions[i++] = iti.position - (places - place) * iti.distance / places; + positionsCalculated++; } - return; + clusterStart += UTF8BytesOfLead[static_cast<unsigned char>(utfForm[clusterStart])]; + place++; } - PLATFORM_ASSERT(ligatureLength > 0 && ligatureLength <= 3); - for (int charInLig=0; charInLig<ligatureLength; charInLig++) { - positions[i++] = iti.position - (ligatureLength - 1 - charInLig) * iti.distance / ligatureLength; + } + PLATFORM_ASSERT(static_cast<size_t>(i) == text.length()); + } + } + if (positionsCalculated < 1) { + const size_t lenPositions = text.length(); + // Either 8-bit or DBCS conversion failed so treat as 8-bit. + SetConverter(PFont(font_)->characterSet); + const bool rtlCheck = PFont(font_)->characterSet == SC_CHARSET_HEBREW || + PFont(font_)->characterSet == SC_CHARSET_ARABIC; + std::string utfForm = UTF8FromIconv(conv, text); + if (utfForm.empty()) { + utfForm = UTF8FromLatin1(text); + } + pango_layout_set_text(layout, utfForm.c_str(), utfForm.length()); + size_t i = 0; + int clusterStart = 0; + // Each 8-bit input character may take 1 or 2 bytes in UTF-8 + // and groups of up to 3 may be represented as ligatures. + ClusterIterator iti(layout, utfForm.length()); + while (!iti.finished) { + iti.Next(); + const int clusterEnd = iti.curIndex; + const int ligatureLength = g_utf8_strlen(utfForm.c_str() + clusterStart, clusterEnd - clusterStart); + if (rtlCheck && ((clusterEnd <= clusterStart) || (ligatureLength == 0) || (ligatureLength > 3))) { + // Something has gone wrong: exit quickly but pretend all the characters are equally spaced: + int widthLayout = 0; + pango_layout_get_size(layout, &widthLayout, nullptr); + const XYPOSITION widthTotal = floatFromPangoUnits(widthLayout); + for (size_t bytePos=0; bytePos<lenPositions; bytePos++) { + positions[bytePos] = widthTotal / lenPositions * (bytePos + 1); } - clusterStart = clusterEnd; + return; } - while (i < lenPositions) { - // If something failed, fill in rest of the positions - positions[i++] = clusterStart; + PLATFORM_ASSERT(ligatureLength > 0 && ligatureLength <= 3); + for (int charInLig=0; charInLig<ligatureLength; charInLig++) { + positions[i++] = iti.position - (ligatureLength - 1 - charInLig) * iti.distance / ligatureLength; } - PLATFORM_ASSERT(i == text.length()); + clusterStart = clusterEnd; } + while (i < lenPositions) { + // If something failed, fill in rest of the positions + positions[i++] = clusterStart; + } + PLATFORM_ASSERT(i == text.length()); } } } else { @@ -880,37 +863,31 @@ void SurfaceImpl::MeasureWidths(Font &font_, std::string_view text, XYPOSITION * } } -XYPOSITION SurfaceImpl::WidthText(Font &font_, std::string_view text) { - if (font_.GetID()) { - if (PFont(font_)->pfd) { - std::string utfForm; - pango_layout_set_font_description(layout, PFont(font_)->pfd); - if (et == UTF8) { - pango_layout_set_text(layout, text.data(), text.length()); - } else { - SetConverter(PFont(font_)->characterSet); - utfForm = UTF8FromIconv(conv, text); - if (utfForm.empty()) { // iconv failed so treat as Latin1 - utfForm = UTF8FromLatin1(text); - } - pango_layout_set_text(layout, utfForm.c_str(), utfForm.length()); +XYPOSITION SurfaceImpl::WidthText(const Font *font_, std::string_view text) { + if (PFont(font_)->pfd) { + std::string utfForm; + pango_layout_set_font_description(layout, PFont(font_)->pfd); + if (et == UTF8) { + pango_layout_set_text(layout, text.data(), text.length()); + } else { + SetConverter(PFont(font_)->characterSet); + utfForm = UTF8FromIconv(conv, text); + if (utfForm.empty()) { // iconv failed so treat as Latin1 + utfForm = UTF8FromLatin1(text); } - PangoLayoutLine *pangoLine = pango_layout_get_line_readonly(layout, 0); - PangoRectangle pos {}; - pango_layout_line_get_extents(pangoLine, nullptr, &pos); - return floatFromPangoUnits(pos.width); + pango_layout_set_text(layout, utfForm.c_str(), utfForm.length()); } - return 1; - } else { - return 1; + 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(Font &font_) { - if (!(font_.GetID())) - return 1; +XYPOSITION SurfaceImpl::Ascent(const Font *font_) { XYPOSITION ascent = 0; if (PFont(font_)->pfd) { PangoFontMetrics *metrics = pango_context_get_metrics(pcontext, @@ -925,9 +902,7 @@ XYPOSITION SurfaceImpl::Ascent(Font &font_) { return ascent; } -XYPOSITION SurfaceImpl::Descent(Font &font_) { - if (!(font_.GetID())) - return 1; +XYPOSITION SurfaceImpl::Descent(const Font *font_) { if (PFont(font_)->pfd) { PangoFontMetrics *metrics = pango_context_get_metrics(pcontext, PFont(font_)->pfd, pango_context_get_language(pcontext)); @@ -939,15 +914,15 @@ XYPOSITION SurfaceImpl::Descent(Font &font_) { return 0; } -XYPOSITION SurfaceImpl::InternalLeading(Font &) { +XYPOSITION SurfaceImpl::InternalLeading(const Font *) { return 0; } -XYPOSITION SurfaceImpl::Height(Font &font_) { +XYPOSITION SurfaceImpl::Height(const Font *font_) { return Ascent(font_) + Descent(font_); } -XYPOSITION SurfaceImpl::AverageCharWidth(Font &font_) { +XYPOSITION SurfaceImpl::AverageCharWidth(const Font *font_) { return WidthText(font_, "n"); } @@ -1092,7 +1067,7 @@ void Window::InvalidateRectangle(PRectangle rc) { } } -void Window::SetFont(Font &) { +void Window::SetFont(const Font *) { // Can not be done generically but only needed for ListBox } @@ -1240,7 +1215,7 @@ public: } #endif } - void SetFont(Font &font) override; + void SetFont(const Font *font) override; void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_, int technology_) override; void SetAverageCharWidth(int width) override; void SetVisibleRows(int rows) override; @@ -1508,7 +1483,7 @@ void ListBoxX::Create(Window &parent, int, Point, int, bool, int) { GTK_WINDOW(top)); } -void ListBoxX::SetFont(Font &font) { +void ListBoxX::SetFont(const Font *font) { // Only do for Pango font as there have been crashes for GDK fonts if (Created() && PFont(font)->pfd) { // Current font is Pango font |