summaryrefslogtreecommitdiff
path: root/vcl/source
diff options
context:
space:
mode:
authorKhaled Hosny <khaled@aliftype.com>2022-08-28 06:59:06 +0200
committerخالد حسني <khaled@aliftype.com>2022-08-31 08:46:25 +0200
commitbdbbdc9b931d35f6d7d816512ac5be599295dc80 (patch)
treeb83d4ec811c801eec6fa82853fdc28ef32fbd044 /vcl/source
parent51103b8396c3a0c0dc34afcf3c11bd93e4342163 (diff)
tdf#30731: Use ligature caret positions from the font
When ligature caret positions from the font are available, use them for more accurate caret positions instead of evenly distributing the glyph width over grapheme clusters. Change-Id: I0ecfa35e1fff2b264b105182a4b29b2ebd033093 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138955 Tested-by: Jenkins Reviewed-by: خالد حسني <khaled@aliftype.com>
Diffstat (limited to 'vcl/source')
-rw-r--r--vcl/source/gdi/CommonSalLayout.cxx54
1 files changed, 46 insertions, 8 deletions
diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index f75dc12dedd0..014d4f738d9f 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -673,18 +673,56 @@ void GenericSalLayout::GetCharWidths(std::vector<DeviceCoordinate>& rCharWidths,
nGraphemeCount++;
}
+ std::vector<DeviceCoordinate> aWidths(nGraphemeCount);
+
+ // Check if the glyph has ligature caret positions.
+ unsigned int nCarets = nGraphemeCount;
+ std::vector<hb_position_t> aCarets(nGraphemeCount);
+ hb_ot_layout_get_ligature_carets(GetFont().GetHbFont(),
+ aGlyphItem.IsRTLGlyph() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR,
+ aGlyphItem.glyphId(), 0, &nCarets, aCarets.data());
+
+ // Carets are 1-less than the grapheme count (since the last
+ // position is defined by glyph width), if the count does not
+ // match, ignore it.
+ if (nCarets == nGraphemeCount - 1)
+ {
+ // Scale the carets and apply glyph offset to them since they
+ // are based on the default glyph metrics.
+ double fScale = 0;
+ GetFont().GetScale(&fScale, nullptr);
+ for (size_t i = 0; i < nCarets; i++)
+ aCarets[i] = (aCarets[i] * fScale) + aGlyphItem.xOffset();
+
+ // Use the glyph width for the last caret.
+ aCarets[nCarets] = aGlyphItem.newWidth();
+
+ // Carets are absolute from the X origin of the glyph, turn
+ // them to relative widths that we need below.
+ for (size_t i = 0; i < nGraphemeCount; i++)
+ aWidths[i] = aCarets[i] - (i == 0 ? 0 : aCarets[i - 1]);
+
+ // Carets are in visual order, but we want widths in logical
+ // order.
+ if (aGlyphItem.IsRTLGlyph())
+ std::reverse(aWidths.begin(), aWidths.end());
+ }
+ else
+ {
+ // The glyph has no carets, distribute the width evenly.
+ auto nWidth = aGlyphItem.newWidth() / nGraphemeCount;
+ std::fill(aWidths.begin(), aWidths.end(), nWidth);
+
+ // Add rounding difference to the last component to maintain
+ // ligature width.
+ aWidths[nGraphemeCount - 1] += aGlyphItem.newWidth() - (nWidth * nGraphemeCount);
+ }
+
// Set the width of each grapheme cluster.
nPos = aGlyphItem.charPos();
- auto nWidth = aGlyphItem.newWidth() / nGraphemeCount;
- // rounding difference
- auto nDiff = aGlyphItem.newWidth() - (nWidth * nGraphemeCount);
- for (unsigned int i = 0; i < nGraphemeCount; i++)
+ for (auto nWidth : aWidths)
{
rCharWidths[nPos - mnMinCharPos] += nWidth;
- // add rounding difference to last component to maintain
- // ligature width.
- if (i == nGraphemeCount - 1)
- rCharWidths[nPos - mnMinCharPos] += nDiff;
nPos = xBreak->nextCharacters(rStr, nPos, aLocale,
css::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
}