vcl/inc/unx/fc_fontoptions.hxx | 3 ++ vcl/quartz/salgdi.cxx | 38 ++++++++++++++++++++++++++++ vcl/unx/generic/gdi/cairotextrender.cxx | 43 +++++++++++++++++++++++++++++--- 3 files changed, 80 insertions(+), 4 deletions(-)
New commits: commit 33afa8dc1479a21783cc7f92e376449d5c7948d8 Author: Khaled Hosny <[email protected]> AuthorDate: Mon Mar 2 01:02:18 2026 +0200 Commit: Khaled Hosny <[email protected]> CommitDate: Mon Mar 2 01:02:18 2026 +0200 xx Change-Id: I9383b49d2a520fb9c03e9971e802af60eb142969 diff --git a/vcl/inc/unx/fc_fontoptions.hxx b/vcl/inc/unx/fc_fontoptions.hxx index 73bcf3421bc5..5fc1da59a9b0 100644 --- a/vcl/inc/unx/fc_fontoptions.hxx +++ b/vcl/inc/unx/fc_fontoptions.hxx @@ -21,6 +21,8 @@ #include <rtl/string.hxx> #include <vcl/dllapi.h> +#include <hb.h> +#include <vector> typedef struct _FcPattern FcPattern; class VCL_DLLPUBLIC FontConfigFontOptions @@ -31,6 +33,7 @@ public: ~FontConfigFontOptions(); void SyncPattern(const OString& rFileName, sal_uInt32 nFontFace, sal_uInt32 nFontVariation, bool bEmbolden); + void AddVariations(const std::vector<hb_variation_t>& rVariations); FcPattern* GetPattern() const; static void cairo_font_options_substitute(FcPattern* pPattern); private: diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx index af5a620484c8..4ea145303218 100644 --- a/vcl/quartz/salgdi.cxx +++ b/vcl/quartz/salgdi.cxx @@ -382,6 +382,37 @@ void AquaGraphicsBackend::drawTextLayout(const GenericSalLayout& rLayout) } CTFontRef pCTFont = rFont.GetCTFont(); + CTFontRef pVarFont = nullptr; + const auto& variations = rFont.GetVariations(); + if (!variations.empty()) + { + CFMutableDictionaryRef pVarDict = CFDictionaryCreateMutable(kCFAllocatorDefault, variations.size(), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + for (const auto& var : variations) + { + hb_tag_t nTag = var.tag; + CFNumberRef pTag = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &nTag); + double fValue = var.value; + CFNumberRef pValue = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &fValue); + CFDictionaryAddValue(pVarDict, pTag, pValue); + CFRelease(pTag); + CFRelease(pValue); + } + CFDictionaryRef pAttrDict = CFDictionaryCreate(kCFAllocatorDefault, + (const void**)&kCTFontVariationAttribute, + (const void**)&pVarDict, 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CTFontDescriptorRef pVarDesc = CTFontDescriptorCreateWithAttributes(pAttrDict); + pVarFont = CTFontCreateCopyWithAttributes(pCTFont, 0.0, nullptr, pVarDesc); + pCTFont = pVarFont; + + CFRelease(pVarDesc); + CFRelease(pAttrDict); + CFRelease(pVarDict); + } + CGAffineTransform aRotMatrix = CGAffineTransformMakeRotation(-rFont.mfFontRotation); basegfx::B2DPoint aPos; @@ -412,7 +443,11 @@ void AquaGraphicsBackend::drawTextLayout(const GenericSalLayout& rLayout) } if (aGlyphIds.empty()) + { + if (pVarFont) + CFRelease(pVarFont); return; + } assert(aGlyphIds.size() == aGlyphPos.size()); #if 0 @@ -481,6 +516,9 @@ void AquaGraphicsBackend::drawTextLayout(const GenericSalLayout& rLayout) } mrShared.maContextHolder.restoreState(); + + if (pVarFont) + CFRelease(pVarFont); } void AquaSalGraphics::SetFont(LogicalFontInstance* pReqFont, int nFallbackLevel) diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx index 14ee838df33d..c118aa396ee4 100644 --- a/vcl/unx/generic/gdi/cairotextrender.cxx +++ b/vcl/unx/generic/gdi/cairotextrender.cxx @@ -29,8 +29,11 @@ #include <sallayout.hxx> #include <salinst.hxx> +#include <rtl/ustrbuf.hxx> +#include <hb.h> #include <cairo.h> #include <cairo-ft.h> +#include <fontconfig/fontconfig.h> #if defined(CAIRO_HAS_SVG_SURFACE) #include <cairo-svg.h> #elif defined(CAIRO_HAS_PDF_SURFACE) @@ -43,6 +46,10 @@ namespace { typedef struct FT_FaceRec_* FT_Face; +#ifndef FC_FONT_VARIATIONS +#define FC_FONT_VARIATIONS "fontvariations" +#endif + class CairoFontsCache : public CacheOwner { public: @@ -52,12 +59,22 @@ public: const FontConfigFontOptions *mpOptions; bool mbEmbolden; bool mbVerticalMetrics; + std::vector<hb_variation_t> maVariations; bool operator ==(const CacheId& rOther) const { - return maFace == rOther.maFace && - mpOptions == rOther.mpOptions && - mbEmbolden == rOther.mbEmbolden && - mbVerticalMetrics == rOther.mbVerticalMetrics; + if (maFace != rOther.maFace || + mpOptions != rOther.mpOptions || + mbEmbolden != rOther.mbEmbolden || + mbVerticalMetrics != rOther.mbVerticalMetrics || + maVariations.size() != rOther.maVariations.size()) + return false; + for (size_t i = 0; i < maVariations.size(); ++i) + { + if (maVariations[i].tag != rOther.maVariations[i].tag || + maVariations[i].value != rOther.maVariations[i].value) + return false; + } + return true; } }; @@ -227,7 +244,24 @@ static void ApplyFont(cairo_t* cr, const CairoFontsCache::CacheId& rId, double n { const FontConfigFontOptions *pOptions = rId.mpOptions; FcPattern *pPattern = pOptions->GetPattern(); + if (!rId.maVariations.empty()) + { + pPattern = FcPatternDuplicate(pPattern); + OStringBuffer aVarStr; + for (const auto& var : rId.maVariations) + { + if (!aVarStr.isEmpty()) + aVarStr.append(','); + char tag[4]; + hb_tag_to_string(var.tag, tag); + aVarStr.append(tag, 4); + aVarStr.append(tag + "=" + OString::number(var.value)); + } + FcPatternAddString(pPattern, FC_FONT_VARIATIONS, reinterpret_cast<const FcChar8*>(aVarStr.getStr())); + } font_face = cairo_ft_font_face_create_for_pattern(pPattern); + if (!rId.maVariations.empty()) + FcPatternDestroy(pPattern); rCache.CacheFont(font_face, rId); } cairo_set_font_face(cr, font_face); @@ -268,6 +302,7 @@ static CairoFontsCache::CacheId makeCacheId(const GenericSalLayout& rLayout) aId.mpOptions = rFont.GetFontOptions(); aId.mbEmbolden = rInstance.NeedsArtificialBold(); aId.mbVerticalMetrics = false; + aId.maVariations = rInstance.GetVariations(); return aId; }
