Rebased ref, commits from common ancestor:
commit f63faa7bb06cb56b519b001973e3425216c4539b
Author: Khaled Hosny <[email protected]>
AuthorDate: Fri Feb 27 03:46:19 2026 +0200
Commit: Khaled Hosny <[email protected]>
CommitDate: Sun Mar 1 18:32:51 2026 +0200
tdf#153368: Support optical size for variable fonts, part 7
Enable in Draw/Impress.
WIP.
Change-Id: Icdfa639836efeb7ae8baa9ffadef35b6ccf28646
diff --git a/include/editeng/unoprnms.hxx b/include/editeng/unoprnms.hxx
index 33662cf3ac9f..b5d354d695bf 100644
--- a/include/editeng/unoprnms.hxx
+++ b/include/editeng/unoprnms.hxx
@@ -319,6 +319,7 @@ inline constexpr OUString UNO_NAME_EDIT_CHAR_FONTCHARSET =
u"CharFontCharSet"_us
inline constexpr OUString UNO_NAME_EDIT_CHAR_FONTPITCH = u"CharFontPitch"_ustr;
inline constexpr OUString UNO_NAME_EDIT_CHAR_POSTURE = u"CharPosture"_ustr;
inline constexpr OUString UNO_NAME_EDIT_CHAR_WEIGHT = u"CharWeight"_ustr;
+inline constexpr OUString UNO_NAME_EDIT_CHAR_OPTICALSIZING =
u"CharOpticalSizing"_ustr;
inline constexpr OUString UNO_NAME_EDIT_CHAR_LOCALE = u"CharLocale"_ustr;
inline constexpr OUString UNO_NAME_EDIT_CHAR_HEIGHT_ASIAN =
u"CharHeightAsian"_ustr;
diff --git a/include/editeng/unotext.hxx b/include/editeng/unotext.hxx
index 37e82293dbb3..65824411a0bd 100644
--- a/include/editeng/unotext.hxx
+++ b/include/editeng/unotext.hxx
@@ -137,7 +137,8 @@ struct SfxItemPropertyMapEntry;
{ UNO_NAME_EDIT_CHAR_RUBY_TEXT, EE_CHAR_RUBY,
::cppu::UnoType<OUString>::get(), 0, MID_RUBY_TEXT }, \
{ UNO_NAME_EDIT_CHAR_RUBY_ADJUST, EE_CHAR_RUBY,
::cppu::UnoType<sal_Int16>::get(), 0, MID_RUBY_ADJUST }, \
{ UNO_NAME_EDIT_CHAR_RUBY_POSITION, EE_CHAR_RUBY,
::cppu::UnoType<sal_Int16>::get(), 0, MID_RUBY_POSITION }, \
- { UNO_NAME_EDIT_CHAR_SCRIPT_HINT, EE_CHAR_SCRIPT_HINT,
::cppu::UnoType<sal_Int16>::get(), 0, MID_SCRIPTHINT }
+ { UNO_NAME_EDIT_CHAR_SCRIPT_HINT, EE_CHAR_SCRIPT_HINT,
::cppu::UnoType<sal_Int16>::get(), 0, MID_SCRIPTHINT }, \
+ { UNO_NAME_EDIT_CHAR_OPTICALSIZING, EE_CHAR_OPTICALSIZING,
::cppu::UnoType<bool>::get(), 0, 0 }
#define SVX_UNOEDIT_FONT_PROPERTIES \
diff --git a/sd/qa/unit/export-tests.cxx b/sd/qa/unit/export-tests.cxx
index 386b42fcdf3f..836d97527479 100644
--- a/sd/qa/unit/export-tests.cxx
+++ b/sd/qa/unit/export-tests.cxx
@@ -2558,6 +2558,74 @@ CPPUNIT_TEST_FIXTURE(SdExportTest,
testTableBordersTransparancy)
Color(ColorTransparency, aBorderLine.Color));
}
+// CharOpticalSizing
+CPPUNIT_TEST_FIXTURE(SdExportTest, testOpticalSizing)
+{
+ createSdImpressDoc();
+
+ uno::Reference<drawing::XDrawPagesSupplier>
xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPages> xDrawPages =
xDrawPagesSupplier->getDrawPages();
+ uno::Reference<drawing::XDrawPage>
xDrawPage(xDrawPages->insertNewByIndex(0),
+ uno::UNO_SET_THROW);
+ uno::Reference<drawing::XShapes> xShapes(xDrawPage, uno::UNO_QUERY_THROW);
+
+ uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent,
uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xNewShape(
+ xFactory->createInstance(u"com.sun.star.drawing.TextShape"_ustr),
uno::UNO_QUERY_THROW);
+ xShapes->add(xNewShape);
+
+ uno::Reference<text::XText> xText(xNewShape, uno::UNO_QUERY_THROW);
+ xText->setString(u"test"_ustr);
+
+ uno::Reference<beans::XPropertySet> xNewShapeProps(xNewShape,
uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextRange> const
xNewParagraph(getParagraphFromShape(0, xNewShapeProps));
+ uno::Reference<text::XTextRange> xNewRun(getRunFromParagraph(0,
xNewParagraph));
+ uno::Reference<beans::XPropertySet> xNewRunProps(xNewRun,
uno::UNO_QUERY_THROW);
+
+ // it should be true by default for new documents
+ CPPUNIT_ASSERT_EQUAL(true,
+
xNewRunProps->getPropertyValue(u"CharOpticalSizing"_ustr).get<bool>());
+
+ //XXXX
+
+ // Setting it manually should set it in contents
+ xNewRunProps->setPropertyValue(u"CharOpticalSizing"_ustr, uno::Any(false));
+ save(TestFilter::ODP);
+ xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
+ assertXPath(pXmlDoc,
"//style:style/style:text-properties[@loext:font-optical-sizing='none']",
+ 1);
+
+ xNewRunProps->setPropertyValue(u"CharOpticalSizing"_ustr, uno::Any(true));
+ save(TestFilter::ODP);
+ pXmlDoc = parseExport(u"content.xml"_ustr);
+ assertXPath(pXmlDoc,
"//style:style/style:text-properties[@loext:font-optical-sizing='auto']",
+ 1);
+
+ saveAndReload(TestFilter::ODP);
+ uno::Reference<beans::XPropertySet> xNewShapeProps2(getShapeFromPage(0,
1));
+ uno::Reference<text::XTextRange> const xNewParagraph2(
+ getParagraphFromShape(0, xNewShapeProps2));
+ uno::Reference<text::XTextRange> xNewRun2(getRunFromParagraph(0,
xNewParagraph2));
+ uno::Reference<beans::XPropertySet> xNewRunProps2(xNewRun2,
uno::UNO_QUERY_THROW);
+ // and it should be true after save-and-reload
+ CPPUNIT_ASSERT_EQUAL(true,
+
xNewRunProps2->getPropertyValue(u"CharOpticalSizing"_ustr).get<bool>());
+
+ pXmlDoc = parseExport(u"content.xml"_ustr);
+ assertXPath(pXmlDoc,
"//style:style/style:text-properties[@loext:font-optical-sizing='auto']",
+ 1);
+
+ dispose();
+
+ createSdImpressDoc("odp/transparent_background.odp");
+ uno::Reference<beans::XPropertySet> xShape(getShapeFromPage(1, 0));
+ uno::Reference<text::XTextRange> const xParagraph(getParagraphFromShape(0,
xShape));
+ uno::Reference<text::XTextRange> xRun(getRunFromParagraph(0, xParagraph));
+ uno::Reference<beans::XPropertySet> xRunProps(xRun, uno::UNO_QUERY_THROW);
+ // but it should be false by default for old documents
+ CPPUNIT_ASSERT_EQUAL(false,
xRunProps->getPropertyValue(u"CharOpticalSizing"_ustr).get<bool>());
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/core/drawdoc4.cxx b/sd/source/core/drawdoc4.cxx
index 772507eb04b9..a089e446ddb5 100644
--- a/sd/source/core/drawdoc4.cxx
+++ b/sd/source/core/drawdoc4.cxx
@@ -78,6 +78,7 @@
#include <editeng/udlnitem.hxx>
#include <editeng/contouritem.hxx>
#include <editeng/emphasismarkitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/shdditem.hxx>
#include <editeng/cmapitem.hxx>
@@ -274,6 +275,7 @@ void SdDrawDocument::CreateLayoutTemplates()
// #i16874# enable kerning by default but only for new documents
rISet.Put(SvxAutoKernItem(true, EE_CHAR_PAIRKERNING));
+ rISet.Put(SvxOpticalSizingItem(true, EE_CHAR_OPTICALSIZING));
// Bullet
// BulletItem and BulletFont for title and outline
diff --git a/sd/source/core/stlpool.cxx b/sd/source/core/stlpool.cxx
index 7316a8f6a547..cb9773c2baf0 100644
--- a/sd/source/core/stlpool.cxx
+++ b/sd/source/core/stlpool.cxx
@@ -41,6 +41,7 @@
#include <editeng/ulspitem.hxx>
#include <editeng/numitem.hxx>
#include <editeng/cmapitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <svl/hint.hxx>
#include <editeng/charreliefitem.hxx>
#include <editeng/emphasismarkitem.hxx>
@@ -249,6 +250,7 @@ void
SdStyleSheetPool::CreateLayoutStyleSheets(std::u16string_view rLayoutName,
rSet.Put( makeSdrTextAutoGrowHeightItem(false) );
// #i16874# enable kerning by default but only for new
documents
rSet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+ rSet.Put(SvxOpticalSizingItem(true, EE_CHAR_OPTICALSIZING));
vcl::Font f( GetBulletFont() );
PutNumBulletItem( pSheet, f );
@@ -359,6 +361,7 @@ void
SdStyleSheetPool::CreateLayoutStyleSheets(std::u16string_view rLayoutName,
rTitleSet.Put( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) );
// #i16874# enable kerning by default but only for new documents
rTitleSet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+ rTitleSet.Put(SvxOpticalSizingItem(true, EE_CHAR_OPTICALSIZING));
aBulletFont.SetFontSize(Size(0,1552)); // 44 pt
PutNumBulletItem( pSheet, aBulletFont );
@@ -405,6 +408,7 @@ void
SdStyleSheetPool::CreateLayoutStyleSheets(std::u16string_view rLayoutName,
rSubtitleSet.Put( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) );
// #i16874# enable kerning by default but only for new documents
rSubtitleSet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+ rSubtitleSet.Put(SvxOpticalSizingItem(true, EE_CHAR_OPTICALSIZING));
aSvxLRSpaceItem.SetTextLeft(SvxIndentValue::zero());
rSubtitleSet.Put(aSvxLRSpaceItem);
@@ -454,6 +458,7 @@ void
SdStyleSheetPool::CreateLayoutStyleSheets(std::u16string_view rLayoutName,
SvxIndentValue::twips(-600.0),
EE_PARA_LRSPACE));
// #i16874# enable kerning by default but only for new documents
rNotesSet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+ rNotesSet.Put(SvxOpticalSizingItem(true, EE_CHAR_OPTICALSIZING));
/* #i35937# */
@@ -479,6 +484,7 @@ void
SdStyleSheetPool::CreateLayoutStyleSheets(std::u16string_view rLayoutName,
// #i16874# enable kerning by default but only for new documents
rBackgroundObjectsSet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING
) );
rBackgroundObjectsSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_BLOCK));
+ rBackgroundObjectsSet.Put(SvxOpticalSizingItem(true,
EE_CHAR_OPTICALSIZING));
}
/**************************************************************************
@@ -498,6 +504,7 @@ void
SdStyleSheetPool::CreateLayoutStyleSheets(std::u16string_view rLayoutName,
rBackgroundSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
// #i16874# enable kerning by default but only for new documents
rBackgroundSet.Put( SvxAutoKernItem( true, EE_CHAR_PAIRKERNING ) );
+ rBackgroundSet.Put(SvxOpticalSizingItem(true, EE_CHAR_OPTICALSIZING));
}
DBG_ASSERT( !bCheck || !bCreated, "missing layout style sheets detected!"
);
commit f1d74fb245ee04f40743c81f8f75bf05ac938511
Author: Khaled Hosny <[email protected]>
AuthorDate: Thu Feb 26 14:28:03 2026 +0200
Commit: Khaled Hosny <[email protected]>
CommitDate: Sun Mar 1 18:32:51 2026 +0200
tdf#153368: Support optical size for variable fonts, part 6
Add Optical Font Sizing checkbox to the Position page of Character
dialog. I’m not sure if this is the best place, but I have no better
idea.
Change-Id: Ice019da856dbd9f1195941706f26b175bb931c97
diff --git a/cui/source/inc/chardlg.hxx b/cui/source/inc/chardlg.hxx
index e3f1240774f6..ef2b99761410 100644
--- a/cui/source/inc/chardlg.hxx
+++ b/cui/source/inc/chardlg.hxx
@@ -272,6 +272,7 @@ private:
std::unique_ptr<weld::MetricSpinButton> m_xKerningMF;
std::unique_ptr<weld::CheckButton> m_xPairKerningBtn;
std::unique_ptr<weld::CheckButton> m_xNoHyphenationBtn;
+ std::unique_ptr<weld::CheckButton> m_xOpticalSizingBtn;
void Initialize();
void UpdatePreview_Impl( sal_uInt8 nProp, sal_uInt8
nEscProp, short nEsc );
@@ -284,6 +285,7 @@ private:
DECL_LINK(KerningModifyHdl_Impl, weld::MetricSpinButton&, void);
DECL_LINK(ValueChangedHdl_Impl, weld::MetricSpinButton&, void);
DECL_LINK(ScaleWidthModifyHdl_Impl, weld::MetricSpinButton&, void);
+ DECL_LINK(OpticalSizingHdl_Impl, weld::Toggleable&, void);
void FontModifyHdl_Impl();
public:
diff --git a/cui/source/tabpages/chardlg.cxx b/cui/source/tabpages/chardlg.cxx
index a1a0130ac6c6..8b86acec9a8b 100644
--- a/cui/source/tabpages/chardlg.cxx
+++ b/cui/source/tabpages/chardlg.cxx
@@ -44,6 +44,7 @@
#include <editeng/autokernitem.hxx>
#include <editeng/nhypitem.hxx>
#include <editeng/colritem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <dialmgr.hxx>
#include <sfx2/htmlmode.hxx>
#include <svx/cuicharmap.hxx>
@@ -78,7 +79,8 @@ const WhichRangesContainer
SvxCharNamePage::pNameRanges(svl::Items<
SID_ATTR_CHAR_COLOR, SID_ATTR_CHAR_COLOR,
SID_ATTR_CHAR_LANGUAGE, SID_ATTR_CHAR_LANGUAGE,
SID_ATTR_CHAR_CJK_FONT, SID_ATTR_CHAR_CJK_WEIGHT,
- SID_ATTR_CHAR_CTL_FONT, SID_ATTR_CHAR_CTL_WEIGHT
+ SID_ATTR_CHAR_CTL_FONT, SID_ATTR_CHAR_CTL_WEIGHT,
+ SID_ATTR_CHAR_OPTICAL_SIZING, SID_ATTR_CHAR_OPTICAL_SIZING
>);
const WhichRangesContainer SvxCharEffectsPage::pEffectsRanges(svl::Items<
@@ -373,7 +375,8 @@ namespace
const SvxLanguageBox* _pLanguageLB,
const FontList* _pFontList,
sal_uInt16 _nFontWhich,
- sal_uInt16 _nFontHeightWhich)
+ sal_uInt16 _nFontHeightWhich,
+ sal_uInt16 _nOpticalSizingWhich)
{
Size aSize = _rFont.GetFontSize();
aSize.setWidth( 0 );
@@ -431,6 +434,10 @@ namespace
_rFont.SetWeight( aFontMetrics.GetWeightMaybeAskConfig() );
_rFont.SetItalic( aFontMetrics.GetItalicMaybeAskConfig() );
_rFont.SetFontSize( aFontMetrics.GetFontSize() );
+ bool bOpticalSizing = false;
+ if (_pPage->GetItemSet().GetItemState(_nOpticalSizingWhich) >=
SfxItemState::DEFAULT)
+ bOpticalSizing = static_cast<const
SvxOpticalSizingItem&>(_pPage->GetItemSet().Get(_nOpticalSizingWhich)).GetValue();
+ _rFont.SetOpticalSizing(bOpticalSizing);
return aFontMetrics;
}
@@ -448,21 +455,21 @@ void SvxCharNamePage::UpdatePreview_Impl()
FontMetric aWestFontMetric = calcFontMetrics(rFont, this,
m_xWestFontNameLB.get(),
m_xWestFontStyleLB.get(), m_xWestFontSizeLB.get(),
m_xWestFontLanguageLB.get(),
&rFontList, GetWhich(SID_ATTR_CHAR_FONT),
- GetWhich(SID_ATTR_CHAR_FONTHEIGHT));
+ GetWhich(SID_ATTR_CHAR_FONTHEIGHT),
GetWhich(SID_ATTR_CHAR_OPTICAL_SIZING));
m_xWestFontTypeFT->set_label(rFontList.GetFontMapText(aWestFontMetric));
FontMetric aEastFontMetric = calcFontMetrics(rCJKFont, this,
m_xEastFontNameLB.get(),
m_xEastFontStyleLB.get(), m_xEastFontSizeLB.get(),
m_xEastFontLanguageLB.get(),
&rFontList, GetWhich(SID_ATTR_CHAR_CJK_FONT),
- GetWhich(SID_ATTR_CHAR_CJK_FONTHEIGHT));
+ GetWhich(SID_ATTR_CHAR_CJK_FONTHEIGHT),
GetWhich(SID_ATTR_CHAR_OPTICAL_SIZING));
m_xEastFontTypeFT->set_label(rFontList.GetFontMapText(aEastFontMetric));
FontMetric aCTLFontMetric = calcFontMetrics(rCTLFont,
this, m_xCTLFontNameLB.get(), m_xCTLFontStyleLB.get(),
m_xCTLFontSizeLB.get(),
m_xCTLFontLanguageLB.get(), &rFontList,
GetWhich(SID_ATTR_CHAR_CTL_FONT),
- GetWhich(SID_ATTR_CHAR_CTL_FONTHEIGHT));
+ GetWhich(SID_ATTR_CHAR_CTL_FONTHEIGHT),
GetWhich(SID_ATTR_CHAR_OPTICAL_SIZING));
m_xCTLFontTypeFT->set_label(rFontList.GetFontMapText(aCTLFontMetric));
@@ -1241,6 +1248,7 @@ bool SvxCharNamePage::FillItemSet( SfxItemSet* rSet )
bool bModified = FillItemSet_Impl( *rSet, Western );
bModified |= FillItemSet_Impl( *rSet, Asian );
bModified |= FillItemSet_Impl( *rSet, Ctl );
+
return bModified;
}
@@ -2443,6 +2451,7 @@ SvxCharPositionPage::SvxCharPositionPage(weld::Container*
pPage, weld::DialogCon
, m_xKerningMF(m_xBuilder->weld_metric_spin_button(u"kerningsb"_ustr,
FieldUnit::POINT))
, m_xPairKerningBtn(m_xBuilder->weld_check_button(u"pairkerning"_ustr))
, m_xNoHyphenationBtn(m_xBuilder->weld_check_button(u"nohyphenation"_ustr))
+ , m_xOpticalSizingBtn(m_xBuilder->weld_check_button(u"opticalsizing"_ustr))
{
m_xPreviewWin.reset(new weld::CustomWeld(*m_xBuilder, u"preview"_ustr,
m_aPreviewWin));
#ifdef IOS
@@ -2486,6 +2495,7 @@ void SvxCharPositionPage::Initialize()
m_xFitToLineCB->connect_toggled(LINK(this, SvxCharPositionPage,
FitToLineHdl_Impl));
m_xKerningMF->connect_value_changed(LINK(this, SvxCharPositionPage,
KerningModifyHdl_Impl));
m_xScaleWidthMF->connect_value_changed(LINK(this, SvxCharPositionPage,
ScaleWidthModifyHdl_Impl));
+ m_xOpticalSizingBtn->connect_toggled(LINK(this, SvxCharPositionPage,
OpticalSizingHdl_Impl));
}
void SvxCharPositionPage::UpdatePreview_Impl( sal_uInt8 nProp, sal_uInt8
nEscProp, short nEsc )
@@ -2639,6 +2649,20 @@ IMPL_LINK_NOARG(SvxCharPositionPage,
ScaleWidthModifyHdl_Impl, weld::MetricSpinB
m_aPreviewWin.SetFontWidthScale(sal_uInt16(m_xScaleWidthMF->get_value(FieldUnit::PERCENT)));
}
+IMPL_LINK_NOARG(SvxCharPositionPage, OpticalSizingHdl_Impl, weld::Toggleable&,
void)
+{
+ SvxFont& rFont = GetPreviewFont();
+ SvxFont& rCJKFont = GetPreviewCJKFont();
+ SvxFont& rCTLFont = GetPreviewCTLFont();
+
+ bool bOpticalSizing = m_xOpticalSizingBtn->get_active();
+ rFont.SetOpticalSizing(bOpticalSizing);
+ rCJKFont.SetOpticalSizing(bOpticalSizing);
+ rCTLFont.SetOpticalSizing(bOpticalSizing);
+
+ m_aPreviewWin.Invalidate();
+}
+
DeactivateRC SvxCharPositionPage::DeactivatePage( SfxItemSet* _pSet )
{
if ( _pSet )
@@ -2818,6 +2842,20 @@ void SvxCharPositionPage::Reset( const SfxItemSet* rSet )
else
m_xNoHyphenationBtn->set_active(false);
+ // Optical Sizing
+ nWhich = GetWhich(SID_ATTR_CHAR_OPTICAL_SIZING);
+ if (rSet->GetItemState(nWhich) >= SfxItemState::DEFAULT)
+ {
+ const SvxOpticalSizingItem& rItem = static_cast<const
SvxOpticalSizingItem&>(rSet->Get(nWhich));
+ m_xOpticalSizingBtn->set_active(rItem.GetValue());
+ }
+ else
+ m_xOpticalSizingBtn->set_active(false);
+ bool bOpticalSizing = m_xOpticalSizingBtn->get_active();
+ rFont.SetOpticalSizing(bOpticalSizing);
+ rCJKFont.SetOpticalSizing(bOpticalSizing);
+ rCTLFont.SetOpticalSizing(bOpticalSizing);
+
// Scale Width
nWhich = GetWhich( SID_ATTR_CHAR_SCALEWIDTH );
if ( rSet->GetItemState( nWhich ) >= SfxItemState::DEFAULT )
@@ -2897,6 +2935,7 @@ void SvxCharPositionPage::ChangesApplied()
m_xKerningMF->save_value();
m_xPairKerningBtn->save_state();
m_xNoHyphenationBtn->save_state();
+ m_xOpticalSizingBtn->save_state();
}
bool SvxCharPositionPage::FillItemSet( SfxItemSet* rSet )
@@ -2998,6 +3037,16 @@ bool SvxCharPositionPage::FillItemSet( SfxItemSet* rSet )
else if ( SfxItemState::DEFAULT == rOldSet.GetItemState( nWhich, false ) )
rSet->InvalidateItem(nWhich);
+ // Optical Sizing
+ nWhich = GetWhich(SID_ATTR_CHAR_OPTICAL_SIZING);
+ if (m_xOpticalSizingBtn->get_state_changed_from_saved())
+ {
+ rSet->Put(SvxOpticalSizingItem(m_xOpticalSizingBtn->get_active(),
GetWhich(SID_ATTR_CHAR_OPTICAL_SIZING)));
+ bModified = true;
+ }
+ else if (SfxItemState::DEFAULT == rOldSet.GetItemState(nWhich, false))
+ rSet->InvalidateItem(nWhich);
+
// Scale Width
nWhich = GetWhich( SID_ATTR_CHAR_SCALEWIDTH );
if (m_xScaleWidthMF->get_value_changed_from_saved())
diff --git a/cui/uiconfig/ui/positionpage.ui b/cui/uiconfig/ui/positionpage.ui
index a959c7da7ee0..ad8569eeb696 100644
--- a/cui/uiconfig/ui/positionpage.ui
+++ b/cui/uiconfig/ui/positionpage.ui
@@ -499,6 +499,54 @@
<property name="position">3</property>
</packing>
</child>
+ <child>
+ <object class="GtkFrame" id="frame9">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label-xalign">0</property>
+ <property name="shadow-type">none</property>
+ <child>
+ <object class="GtkBox" id="box9">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkCheckButton" id="opticalsizing">
+ <property name="label" translatable="yes"
context="positionpage|opticalsizing">Auto</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">False</property>
+ <property name="tooltip-text" translatable="yes"
context="positionpage|opticalsizing">Enable optical font sizing based on font's
point size for fonts that support it</property>
+ <property name="use-underline">True</property>
+ <property name="draw-indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label25">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes"
context="positionpage|label25">Optical Font Sizing</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
@@ -534,7 +582,7 @@
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
- <property name="position">4</property>
+ <property name="position">5</property>
</packing>
</child>
</object>
commit 695857a4bf80cf450d54bb740fd4a10a69141a71
Author: Khaled Hosny <[email protected]>
AuthorDate: Thu Feb 26 22:35:37 2026 +0200
Commit: Khaled Hosny <[email protected]>
CommitDate: Sun Mar 1 18:32:51 2026 +0200
tdf#153368: Support optical size for variable fonts, part 5
Support import/export of font-optical-sizing in HTML filter.
Change-Id: Ib45b3152b57e674fc1e0b4b4b2359634909d15a0
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx
b/sw/qa/extras/htmlexport/htmlexport.cxx
index 20cfe024500f..85fa29ec4c5d 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -1651,6 +1651,33 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest,
testReqifNoTypeInUL)
// Without the accompanying fix in place, this test would have failed
assertXPathNoAttribute(pXmlDoc,
"//reqif-xhtml:ul/reqif-xhtml:li/reqif-xhtml:ul", "type");
}
+
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testOpticalSizing)
+{
+ createSwDoc();
+ uno::Reference<text::XTextRange> xRun = getRun(getParagraph(1), 1);
+ xRun->setString(u"text"_ustr);
+ uno::Reference<beans::XPropertySet> xCursor(xRun, uno::UNO_QUERY);
+
+ xCursor->setPropertyValue(u"CharOpticalSizing"_ustr, uno::Any(false));
+ saveAndReload(TestFilter::HTML_WRITER);
+
+ uno::Reference<beans::XPropertySet> xRetCursor(getRun(getParagraph(1), 1),
uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xRetCursor,
u"CharOpticalSizing"_ustr));
+
+ dispose();
+
+ createSwDoc();
+ uno::Reference<text::XTextRange> xRun2 = getRun(getParagraph(1), 1);
+ xRun2->setString(u"text"_ustr);
+ uno::Reference<beans::XPropertySet> xCursor2(xRun2, uno::UNO_QUERY);
+
+ xCursor2->setPropertyValue(u"CharOpticalSizing"_ustr, uno::Any(true));
+ saveAndReload(TestFilter::HTML_WRITER);
+
+ uno::Reference<beans::XPropertySet> xRetCursor2(getRun(getParagraph(1),
1), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xRetCursor2,
u"CharOpticalSizing"_ustr));
+}
} // end of anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/filter/html/css1atr.cxx
b/sw/source/filter/html/css1atr.cxx
index 6f80bb53ff47..12334aaac59d 100644
--- a/sw/source/filter/html/css1atr.cxx
+++ b/sw/source/filter/html/css1atr.cxx
@@ -48,6 +48,7 @@
#include <editeng/spltitem.hxx>
#include <editeng/orphitem.hxx>
#include <editeng/charhiddenitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <svx/xoutbmp.hxx>
#include <svx/svdobj.hxx>
#include <editeng/langitem.hxx>
@@ -2549,6 +2550,16 @@ static SwHTMLWriter& OutCSS1_SvxHidden( SwHTMLWriter&
rWrt, const SfxPoolItem& r
return rWrt;
}
+static SwHTMLWriter& OutCSS1_SvxOpticalSizing( SwHTMLWriter& rWrt, const
SfxPoolItem& rHt )
+{
+ if( static_cast<const SvxOpticalSizingItem&>(rHt).GetValue() )
+ rWrt.OutCSS1_PropertyAscii( sCSS1_P_font_optical_sizing, sCSS1_PV_auto
);
+ else
+ rWrt.OutCSS1_PropertyAscii( sCSS1_P_font_optical_sizing, sCSS1_PV_none
);
+
+ return rWrt;
+}
+
static SwHTMLWriter& OutCSS1_SvxFontWeight( SwHTMLWriter& rWrt, const
SfxPoolItem& rHt )
{
sal_uInt16 nScript = CSS1_OUTMODE_WESTERN;
@@ -3465,7 +3476,7 @@ SwAttrFnTab const aCSS1AttrFnTab = {
/* RES_CHRATR_BIDIRTL */ nullptr,
/* RES_CHRATR_UNUSED3 */ nullptr,
/* RES_CHRATR_SCRIPT_HINT */ nullptr,
-/* RES_CHRATR_OPTICAL_SIZING */ nullptr,
+/* RES_CHRATR_OPTICAL_SIZING */ OutCSS1_SvxOpticalSizing,
/* RES_TXTATR_REFMARK */ nullptr,
/* RES_TXTATR_TOXMARK */ nullptr,
diff --git a/sw/source/filter/html/css1kywd.hxx
b/sw/source/filter/html/css1kywd.hxx
index 2548cd3a9537..8332083ad0f1 100644
--- a/sw/source/filter/html/css1kywd.hxx
+++ b/sw/source/filter/html/css1kywd.hxx
@@ -65,6 +65,7 @@ constexpr inline std::string_view sCSS1_PV_italic = "italic";
constexpr inline std::string_view sCSS1_PV_oblique = "oblique";
constexpr inline std::string_view sCSS1_P_font_variant = "font-variant";
+constexpr inline std::string_view sCSS1_P_font_optical_sizing =
"font-optical-sizing";
//constexpr inline std::string_view sCSS1_PV_normal = "normal";
constexpr inline std::string_view sCSS1_PV_small_caps = "small-caps";
diff --git a/sw/source/filter/html/htmlatr.cxx
b/sw/source/filter/html/htmlatr.cxx
index d917fea69094..cc33bf540ff4 100644
--- a/sw/source/filter/html/htmlatr.cxx
+++ b/sw/source/filter/html/htmlatr.cxx
@@ -45,6 +45,7 @@
#include <editeng/lrspitem.hxx>
#include <editeng/langitem.hxx>
#include <editeng/frmdiritem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <fchrfmt.hxx>
#include <fmtautofmt.hxx>
#include <fmtfsize.hxx>
@@ -3316,7 +3317,7 @@ const SwAttrFnTab aHTMLAttrFnTab = {
/* RES_CHRATR_BIDIRTL */ nullptr,
/* RES_CHRATR_UNUSED3 */ nullptr,
/* RES_CHRATR_SCRIPT_HINT */ nullptr,
-/* RES_CHRATR_OPTICAL_SIZING */ nullptr,
+/* RES_CHRATR_OPTICAL_SIZING */ OutHTML_CSS1Attr,
/* RES_TXTATR_REFMARK */ nullptr,
/* RES_TXTATR_TOXMARK */ nullptr,
diff --git a/sw/source/filter/html/htmlcss1.cxx
b/sw/source/filter/html/htmlcss1.cxx
index 5229d3c69eb5..cc0bb8d90cd8 100644
--- a/sw/source/filter/html/htmlcss1.cxx
+++ b/sw/source/filter/html/htmlcss1.cxx
@@ -1598,6 +1598,9 @@ HTMLAttr **SwHTMLParser::GetAttrTabEntry( sal_uInt16
nWhich )
case RES_CHRATR_BACKGROUND:
ppAttr = &m_xAttrTab->pCharBrush;
break;
+ case RES_CHRATR_OPTICAL_SIZING:
+ ppAttr = &m_xAttrTab->pOpticalSizing;
+ break;
case RES_CHRATR_BOX:
ppAttr = &m_xAttrTab->pCharBox;
break;
diff --git a/sw/source/filter/html/svxcss1.cxx
b/sw/source/filter/html/svxcss1.cxx
index 69cc2f381cd4..ffd8dd0a7982 100644
--- a/sw/source/filter/html/svxcss1.cxx
+++ b/sw/source/filter/html/svxcss1.cxx
@@ -52,6 +52,7 @@
#include <editeng/widwitem.hxx>
#include <editeng/frmdiritem.hxx>
#include <editeng/orphitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <utility>
#include <vcl/metric.hxx>
#include <vcl/svapp.hxx>
@@ -283,6 +284,7 @@ struct SvxCSS1ItemIds
sal_uInt16 nKerning;
sal_uInt16 nCaseMap;
sal_uInt16 nBlink;
+ sal_uInt16 nOpticalSizing;
sal_uInt16 nLineSpacing;
sal_uInt16 nAdjust;
@@ -738,6 +740,7 @@ SvxCSS1Parser::SvxCSS1Parser( SfxItemPool& rPool, OUString
aBaseURL,
aItemIds.nKerning = initTrueWhich( SID_ATTR_CHAR_KERNING );
aItemIds.nCaseMap = initTrueWhich( SID_ATTR_CHAR_CASEMAP );
aItemIds.nBlink = initTrueWhich( SID_ATTR_FLASH );
+ aItemIds.nOpticalSizing = initTrueWhich( SID_ATTR_CHAR_OPTICAL_SIZING );
aItemIds.nLineSpacing = initTrueWhich( SID_ATTR_PARA_LINESPACE );
aItemIds.nAdjust = initTrueWhich( SID_ATTR_PARA_ADJUST );
@@ -1247,6 +1250,28 @@ static void ParseCSS1_font_variant( const CSS1Expression
*pExpr,
}
}
+static void ParseCSS1_font_optical_sizing( const CSS1Expression *pExpr,
+ SfxItemSet &rItemSet,
+ SvxCSS1PropertyInfo& /*rPropInfo*/,
+ const SvxCSS1Parser& /*rParser*/ )
+{
+ assert(pExpr && "no expression");
+
+ switch( pExpr->GetType() )
+ {
+ case CSS1_IDENT:
+ {
+ if( o3tl::equalsIgnoreAsciiCase( pExpr->GetString(), sCSS1_PV_auto
) )
+ rItemSet.Put( SvxOpticalSizingItem( true,
aItemIds.nOpticalSizing ) );
+ else if( o3tl::equalsIgnoreAsciiCase( pExpr->GetString(),
sCSS1_PV_none ) )
+ rItemSet.Put( SvxOpticalSizingItem( false,
aItemIds.nOpticalSizing ) );
+ break;
+ }
+ default:
+ break;
+ }
+}
+
static void ParseCSS1_text_transform( const CSS1Expression *pExpr,
SfxItemSet &rItemSet,
SvxCSS1PropertyInfo& /*rPropInfo*/,
@@ -3099,6 +3124,7 @@ CSS1PropEntry constexpr aCSS1PropFnTab[] =
{ sCSS1_P_float, ParseCSS1_float },
{ sCSS1_P_font, ParseCSS1_font },
{ sCSS1_P_font_family, ParseCSS1_font_family },
+ { sCSS1_P_font_optical_sizing, ParseCSS1_font_optical_sizing },
{ sCSS1_P_font_size, ParseCSS1_font_size },
{ sCSS1_P_font_style, ParseCSS1_font_style },
{ sCSS1_P_font_variant, ParseCSS1_font_variant },
diff --git a/sw/source/filter/html/swhtml.hxx b/sw/source/filter/html/swhtml.hxx
index 151189aa7acf..5147d8e8c6fa 100644
--- a/sw/source/filter/html/swhtml.hxx
+++ b/sw/source/filter/html/swhtml.hxx
@@ -128,6 +128,7 @@ struct HTMLAttrTable
HTMLAttr* pLanguageCJK;
HTMLAttr* pLanguageCTL;
HTMLAttr* pCharBox;
+ HTMLAttr* pOpticalSizing;
};
class HTMLAttr
commit 2aed32b1be83de428d7a19db58742917fc0bf7ae
Author: Khaled Hosny <[email protected]>
AuthorDate: Thu Feb 26 17:48:05 2026 +0200
Commit: Khaled Hosny <[email protected]>
CommitDate: Sun Mar 1 18:32:50 2026 +0200
Clamp variation values to axis min and max
Avoids creating needless PDF subsets for instances that are effectively
the same.
Change-Id: I9ce04f99a77cb4d6fde5456d6de928b9f46670e2
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index 71ee4c282fc9..3789f713dc4e 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -2197,10 +2197,9 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testOpticalSizing)
}
}
- std::set<OString> aExpected{ "Fraunces_150opsz_400wght"_ostr,
"Fraunces_144opsz_400wght"_ostr,
- "Fraunces_80opsz_400wght"_ostr,
"Fraunces_60opsz_400wght"_ostr,
- "Fraunces_40opsz_400wght"_ostr,
"Fraunces_20opsz_400wght"_ostr,
- "Fraunces_6opsz_400wght"_ostr,
"Fraunces-Regular"_ostr };
+ std::set<OString> aExpected{ "Fraunces_144opsz_400wght"_ostr,
"Fraunces_80opsz_400wght"_ostr,
+ "Fraunces_60opsz_400wght"_ostr,
"Fraunces_40opsz_400wght"_ostr,
+ "Fraunces_20opsz_400wght"_ostr,
"Fraunces-Regular"_ostr };
CPPUNIT_ASSERT_EQUAL(aExpected, aFontNames);
#endif
diff --git a/vcl/source/font/LogicalFontInstance.cxx
b/vcl/source/font/LogicalFontInstance.cxx
index edbe0657e69e..fe9f6b3e7ac0 100644
--- a/vcl/source/font/LogicalFontInstance.cxx
+++ b/vcl/source/font/LogicalFontInstance.cxx
@@ -70,8 +70,13 @@ const std::vector<hb_variation_t>&
LogicalFontInstance::GetVariations() const
if (m_bOpticalSizing)
aVariations.push_back({ HB_TAG('o', 'p', 's', 'z'), m_fPointSize
});
- for (const auto& rVariation : aVariations)
+ hb_face_t* pHbFace = GetFontFace()->GetHbFace();
+ for (auto& rVariation : aVariations)
{
+ hb_ot_var_axis_info_t info;
+ if (hb_ot_var_find_axis_info(pHbFace, rVariation.tag, &info))
+ rVariation.value = std::clamp(rVariation.value,
info.min_value, info.max_value);
+
auto it = std::find_if(mxVariations->begin(), mxVariations->end(),
[&rVariation](const hb_variation_t& rOther)
{
return rOther.tag == rVariation.tag;
commit c4cf10f92262dc10a52384e97f61bfb683ae587d
Author: Khaled Hosny <[email protected]>
AuthorDate: Thu Feb 26 14:11:21 2026 +0200
Commit: Khaled Hosny <[email protected]>
CommitDate: Sun Mar 1 18:32:50 2026 +0200
tdf#153368: Support optical size for variable fonts, part 4
Support saving/loading font-optical-sizing in Writer. The
font-optical-sizing property is enabled on the standard style for new
documents, and for old documents it remains unset for backward
compatibility.
Add no-op stubs to DOCX, RTF, WW8, and HTML filters.
Change-Id: I87e3de603785dbd588099bfbd72e13e4538fc420
diff --git a/sw/inc/charatr.hxx b/sw/inc/charatr.hxx
index 3bea7a6d38e7..677088b44d11 100644
--- a/sw/inc/charatr.hxx
+++ b/sw/inc/charatr.hxx
@@ -43,6 +43,7 @@
#include <editeng/langitem.hxx>
#include <editeng/colritem.hxx>
#include <editeng/scripthintitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
// implementation of the character attribute methods of SwAttrSet
@@ -112,6 +113,8 @@ inline const SvxCharReliefItem &SwAttrSet::GetCharRelief(
bool bInP ) const
{ return Get( RES_CHRATR_RELIEF, bInP ); }
inline const SvxCharHiddenItem &SwAttrSet::GetCharHidden( bool bInP ) const
{ return Get( RES_CHRATR_HIDDEN, bInP ); }
+inline const SvxOpticalSizingItem&SwAttrSet::GetOpticalSizing(bool bInP) const
+ { return Get( RES_CHRATR_OPTICAL_SIZING,bInP); }
// implementation of the character attribute methods of SwFormat
diff --git a/sw/inc/hintids.hxx b/sw/inc/hintids.hxx
index 423dafdcea08..59f0c2d51672 100644
--- a/sw/inc/hintids.hxx
+++ b/sw/inc/hintids.hxx
@@ -76,6 +76,7 @@ class SvxLanguageItem;
class SvxLineSpacingItem;
class SvxNoHyphenItem;
class SvxOpaqueItem;
+class SvxOpticalSizingItem;
class SvxOrphansItem;
class SvxOverlineItem;
class SvxPaperBinItem;
@@ -244,7 +245,9 @@ inline constexpr TypedWhichId<SfxGrabBagItem>
RES_CHRATR_GRABBAG(RES_CHRATR_BEGI
inline constexpr TypedWhichId<SfxInt16Item>
RES_CHRATR_BIDIRTL(RES_CHRATR_BEGIN + 43);
inline constexpr TypedWhichId<SfxInt16Item>
RES_CHRATR_UNUSED3(RES_CHRATR_BEGIN + 44);
inline constexpr TypedWhichId<SvxScriptHintItem>
RES_CHRATR_SCRIPT_HINT(RES_CHRATR_BEGIN + 45);
-inline constexpr sal_uInt16 RES_CHRATR_END(RES_CHRATR_BEGIN + 46);
+inline constexpr TypedWhichId<SvxOpticalSizingItem>
RES_CHRATR_OPTICAL_SIZING(RES_CHRATR_BEGIN
+
+ 46);
+inline constexpr sal_uInt16 RES_CHRATR_END(RES_CHRATR_BEGIN + 47);
// this Attribute used only in a TextNodes SwpAttr-Array
inline constexpr sal_uInt16 RES_TXTATR_BEGIN(RES_CHRATR_END);
diff --git a/sw/inc/swatrset.hxx b/sw/inc/swatrset.hxx
index 67709a849665..af13c71880ca 100644
--- a/sw/inc/swatrset.hxx
+++ b/sw/inc/swatrset.hxx
@@ -52,6 +52,7 @@ class SvxCharRotateItem;
class SvxCharReliefItem;
class SvxCharHiddenItem;
class SvxScriptHintItem;
+class SvxOpticalSizingItem;
// Frame attributes
class SwFormatFillOrder;
@@ -244,6 +245,7 @@ public:
inline const SvxCharRotateItem &GetCharRotate( bool = true ) const;
inline const SvxCharReliefItem &GetCharRelief( bool = true ) const;
inline const SvxCharHiddenItem &GetCharHidden( bool = true ) const;
+ inline const SvxOpticalSizingItem &GetOpticalSizing( bool = true ) const;
// Frame attributes. Implementation in frmatr.hxx.
inline const SwFormatFillOrder &GetFillOrder( bool = true ) const;
diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx
index 3d9270fdb429..e30a28c26581 100644
--- a/sw/inc/unoprnms.hxx
+++ b/sw/inc/unoprnms.hxx
@@ -151,6 +151,7 @@ inline constexpr OUString UNO_NAME_CHAR_PROP_HEIGHT_COMPLEX
= u"CharPropHeightCo
inline constexpr OUString UNO_NAME_CHAR_DIFF_HEIGHT_COMPLEX =
u"CharDiffHeightComplex"_ustr;
inline constexpr OUString UNO_NAME_CHAR_ESCAPEMENT_HEIGHT =
u"CharEscapementHeight"_ustr;
inline constexpr OUString UNO_NAME_CHAR_TRANSPARENCE =
u"CharTransparence"_ustr;
+inline constexpr OUString UNO_NAME_CHAR_OPTICAL_SIZING =
u"CharOpticalSizing"_ustr;
inline constexpr OUString UNO_NAME_HIDE_TAB_LEADER_AND_PAGE_NUMBERS
= u"HideTabLeaderAndPageNumber"_ustr;
inline constexpr OUString UNO_NAME_TAB_IN_TOC = u"TabInTOC"_ustr;
diff --git a/sw/qa/extras/odfexport/odfexport.cxx
b/sw/qa/extras/odfexport/odfexport.cxx
index 153b1a56197e..bfbd1092a301 100644
--- a/sw/qa/extras/odfexport/odfexport.cxx
+++ b/sw/qa/extras/odfexport/odfexport.cxx
@@ -1558,7 +1558,40 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf60700_directories)
CPPUNIT_ASSERT_EQUAL(0, nMatches);
}
+// CharOpticalSizing
+CPPUNIT_TEST_FIXTURE(Test, testOpticalSizing)
+{
+ createSwDoc();
+ uno::Reference<beans::XPropertySet> xCursor(getRun(getParagraph(1), 1),
uno::UNO_QUERY);
+ // it should be true by default for new documents
+ CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xCursor,
u"CharOpticalSizing"_ustr));
+
+ // Setting it manually should set it in contents
+ xCursor->setPropertyValue(u"CharOpticalSizing"_ustr, uno::Any(false));
+ save(TestFilter::ODT);
+ xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
+ assertXPath(pXmlDoc,
"//style:style/style:text-properties[@loext:font-optical-sizing='none']", 1);
+
+ xCursor->setPropertyValue(u"CharOpticalSizing"_ustr, uno::Any(true));
+ save(TestFilter::ODT);
+ pXmlDoc = parseExport(u"content.xml"_ustr);
+ assertXPath(pXmlDoc,
"//style:style/style:text-properties[@loext:font-optical-sizing='auto']", 1);
+
+ saveAndReload(TestFilter::ODT);
+ uno::Reference<beans::XPropertySet> xRun(getRun(getParagraph(1), 1),
uno::UNO_QUERY);
+ // and it should be true after save-and-reload
+ CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xRun,
u"CharOpticalSizing"_ustr));
+ pXmlDoc = parseExport(u"content.xml"_ustr);
+ assertXPath(pXmlDoc,
"//style:style/style:text-properties[@loext:font-optical-sizing='auto']", 1);
+
+ dispose();
+
+ createSwDoc("allow-overlap.odt");
+ uno::Reference<beans::XPropertySet> xCursor2(getRun(getParagraph(1), 1),
uno::UNO_QUERY);
+ // but it should be false by default for old documents
+ CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xCursor2,
u"CharOpticalSizing"_ustr));
+}
} // end of anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/uitest/styleInspector/styleInspector.py
b/sw/qa/uitest/styleInspector/styleInspector.py
index 70554e5307c1..fec8f514abc0 100644
--- a/sw/qa/uitest/styleInspector/styleInspector.py
+++ b/sw/qa/uitest/styleInspector/styleInspector.py
@@ -26,7 +26,7 @@ class styleNavigator(UITestCase):
# The cursor is on text without formatting and default style
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style ",
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(157,
len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(158,
len(xListBox.getChild('0').getChild('0').getChildren()))
self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
self.assertEqual(0, len(xListBox.getChild('3').getChildren()))
@@ -36,7 +36,7 @@ class styleNavigator(UITestCase):
# The cursor is on text with direct formatting
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style ",
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(157,
len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(158,
len(xListBox.getChild('0').getChild('0').getChildren()))
self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
@@ -54,7 +54,7 @@ class styleNavigator(UITestCase):
# The cursor is on text with paragraph direct formatting
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style ",
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(157,
len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(158,
len(xListBox.getChild('0').getChild('0').getChildren()))
xParDirFormatting = xListBox.getChild('1')
self.assertEqual(7, len(xParDirFormatting.getChildren()))
@@ -75,7 +75,7 @@ class styleNavigator(UITestCase):
xParStyle = xListBox.getChild('0')
self.assertEqual(3, len(xParStyle.getChildren()))
self.assertEqual("Default Paragraph Style ",
get_state_as_dict(xParStyle.getChild('0'))['Text'])
- self.assertEqual(157, len(xParStyle.getChild('0').getChildren()))
+ self.assertEqual(158, len(xParStyle.getChild('0').getChildren()))
self.assertEqual("Heading ",
get_state_as_dict(xParStyle.getChild('1'))['Text'])
self.assertEqual(28, len(xParStyle.getChild('1').getChildren()))
@@ -116,7 +116,7 @@ class styleNavigator(UITestCase):
xParStyle = xListBox.getChild('0')
self.assertEqual(3, len(xParStyle.getChildren()))
self.assertEqual("Default Paragraph Style ",
get_state_as_dict(xParStyle.getChild('0'))['Text'])
- self.assertEqual(157, len(xParStyle.getChild('0').getChildren()))
+ self.assertEqual(158, len(xParStyle.getChild('0').getChildren()))
self.assertEqual("Body Text ",
get_state_as_dict(xParStyle.getChild('1'))['Text'])
self.assertEqual(6, len(xParStyle.getChild('1').getChildren()))
@@ -151,7 +151,7 @@ class styleNavigator(UITestCase):
# The cursor is on text without metadata
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style ",
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(157,
len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(158,
len(xListBox.getChild('0').getChild('0').getChildren()))
self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
self.assertEqual(0, len(xListBox.getChild('3').getChildren()))
@@ -161,7 +161,7 @@ class styleNavigator(UITestCase):
# The cursor is on text with paragraph metadata showed under
direct paragraph formatting
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style ",
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(157,
len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(158,
len(xListBox.getChild('0').getChild('0').getChildren()))
xParDirFormatting = xListBox.getChild('1')
self.assertEqual(1, len(xParDirFormatting.getChildren()))
@@ -214,7 +214,7 @@ class styleNavigator(UITestCase):
# The cursor is on text without metadata
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style ",
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(157,
len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(158,
len(xListBox.getChild('0').getChild('0').getChildren()))
self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
self.assertEqual(0, len(xListBox.getChild('3').getChildren()))
@@ -224,7 +224,7 @@ class styleNavigator(UITestCase):
# The cursor is on text with paragraph metadata showed under
direct paragraph formatting
self.assertEqual(1, len(xListBox.getChild('1').getChildren()))
self.assertEqual("Default Paragraph Style ",
get_state_as_dict(xListBox.getChild('1').getChild('0'))['Text'])
- self.assertEqual(157,
len(xListBox.getChild('1').getChild('0').getChildren()))
+ self.assertEqual(158,
len(xListBox.getChild('1').getChild('0').getChildren()))
# Outer bookmark
xBookmarkFormatting = xListBox.getChild('0')
@@ -271,7 +271,7 @@ class styleNavigator(UITestCase):
# The cursor is on text without metadata
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style ",
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(157,
len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(158,
len(xListBox.getChild('0').getChild('0').getChildren()))
self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
diff --git a/sw/qa/uitest/styleInspector/tdf137513.py
b/sw/qa/uitest/styleInspector/tdf137513.py
index de29a3be0588..b499dd5bc5e1 100644
--- a/sw/qa/uitest/styleInspector/tdf137513.py
+++ b/sw/qa/uitest/styleInspector/tdf137513.py
@@ -35,7 +35,7 @@ class tdf137513(UITestCase):
self.assertEqual(2, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style ",
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
self.assertEqual("Table Contents ",
get_state_as_dict(xListBox.getChild('0').getChild('1'))['Text'])
- self.assertEqual(157,
len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(158,
len(xListBox.getChild('0').getChild('0').getChildren()))
xTableContent = xListBox.getChild('0').getChild('1')
self.assertEqual(5, len(xTableContent.getChildren()))
diff --git a/sw/source/core/bastyp/init.cxx b/sw/source/core/bastyp/init.cxx
index 9ceb9195a425..c7fd89b47244 100644
--- a/sw/source/core/bastyp/init.cxx
+++ b/sw/source/core/bastyp/init.cxx
@@ -55,6 +55,7 @@
#include <editeng/lspcitem.hxx>
#include <editeng/nhypitem.hxx>
#include <editeng/opaqitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <editeng/orphitem.hxx>
#include <editeng/paravertalignitem.hxx>
#include <editeng/pbinitem.hxx>
@@ -332,6 +333,7 @@ std::unique_ptr<ItemInfoPackage>
createItemInfoPackageSwAttributes()
{ RES_CHRATR_BIDIRTL, new SfxInt16Item( RES_CHRATR_BIDIRTL,
sal_Int16(-1) ), 0, SFX_ITEMINFOFLAG_NONE },
{ RES_CHRATR_UNUSED3, new SfxVoidItem( RES_CHRATR_UNUSED3 ), 0,
SFX_ITEMINFOFLAG_NONE },
{ RES_CHRATR_SCRIPT_HINT, new SvxScriptHintItem(
RES_CHRATR_SCRIPT_HINT ), SID_ATTR_CHAR_SCRIPT_HINT, SFX_ITEMINFOFLAG_NONE },
+ { RES_CHRATR_OPTICAL_SIZING, new SvxOpticalSizingItem( false,
RES_CHRATR_OPTICAL_SIZING ), SID_ATTR_CHAR_OPTICAL_SIZING,
SFX_ITEMINFOFLAG_NONE },
{ RES_TXTATR_REFMARK, new SwFormatRefMark( SwMarkName() ), 0,
SFX_ITEMINFOFLAG_NONE },
{ RES_TXTATR_TOXMARK, createSwTOXMarkForItemInfoPackage(), 0,
SFX_ITEMINFOFLAG_NONE },
diff --git a/sw/source/core/doc/DocumentStylePoolManager.cxx
b/sw/source/core/doc/DocumentStylePoolManager.cxx
index 4b1667a37f05..17ddfbeb49d3 100644
--- a/sw/source/core/doc/DocumentStylePoolManager.cxx
+++ b/sw/source/core/doc/DocumentStylePoolManager.cxx
@@ -57,6 +57,7 @@
#include <editeng/charrotateitem.hxx>
#include <editeng/emphasismarkitem.hxx>
#include <editeng/scriptspaceitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <o3tl/unit_conversion.hxx>
#include <svx/strings.hrc>
#include <svx/dialmgr.hxx>
diff --git a/sw/source/core/doc/dbgoutsw.cxx b/sw/source/core/doc/dbgoutsw.cxx
index 9b739d2575aa..08049eec18b0 100644
--- a/sw/source/core/doc/dbgoutsw.cxx
+++ b/sw/source/core/doc/dbgoutsw.cxx
@@ -126,6 +126,7 @@ static std::map<sal_uInt16,OUString> & GetItemWhichMap()
{ RES_CHRATR_HIDDEN , "CHRATR_HIDDEN" },
{ RES_CHRATR_BOX , "CHRATR_BOX" },
{ RES_CHRATR_SHADOW , "CHRATR_SHADOW" },
+ { RES_CHRATR_OPTICAL_SIZING , "CHRATR_OPTICAL_SIZING" },
{ RES_TXTATR_AUTOFMT , "TXTATR_AUTOFMT" },
{ RES_TXTATR_INETFMT , "TXTATR_INETFMT" },
{ RES_TXTATR_REFMARK , "TXTATR_REFMARK" },
diff --git a/sw/source/core/inc/swfntcch.hxx b/sw/source/core/inc/swfntcch.hxx
index 43c4c0e43e80..6bb893ca0edb 100644
--- a/sw/source/core/inc/swfntcch.hxx
+++ b/sw/source/core/inc/swfntcch.hxx
@@ -18,7 +18,7 @@
*/
#pragma once
-#define NUM_DEFAULT_VALUES 40
+#define NUM_DEFAULT_VALUES 41
#include "swfont.hxx"
diff --git a/sw/source/core/inc/swfont.hxx b/sw/source/core/inc/swfont.hxx
index a99fdb6fc3a6..afe346863acc 100644
--- a/sw/source/core/inc/swfont.hxx
+++ b/sw/source/core/inc/swfont.hxx
@@ -103,6 +103,7 @@ class SwSubFont final : public SvxFont
inline void SetWordLineMode( const bool bWordLineMode );
inline void SetEmphasisMark( const FontEmphasisMark eValue );
inline void SetRelief( const FontRelief eNew );
+ inline void SetOpticalSizing( bool bOpticalSizing );
// methods for sub-/superscript
inline void SetEscapement( const short nNewEsc );
@@ -235,6 +236,7 @@ public:
inline void SetFixKerning( const short nNewKern );
inline void SetCaseMap( const SvxCaseMap eNew );
inline void SetEmphasisMark( const FontEmphasisMark eValue );
+ inline void SetOpticalSizing( bool bOpticalSizing );
// methods for sub-/superscript
inline void SetEscapement( const short nNewEsc );
@@ -707,6 +709,20 @@ inline void SwFont::SetEmphasisMark( const
FontEmphasisMark eValue )
m_aSub[SwFontScript::CTL].SetEmphasisMark( eValue );
}
+inline void SwSubFont::SetOpticalSizing( bool bOpticalSizing )
+{
+ m_nFontCacheId = nullptr;
+ Font::SetOpticalSizing( bOpticalSizing );
+}
+
+inline void SwFont::SetOpticalSizing( bool bOpticalSizing )
+{
+ m_bFontChg = true;
+ m_aSub[SwFontScript::Latin].SetOpticalSizing( bOpticalSizing );
+ m_aSub[SwFontScript::CJK].SetOpticalSizing( bOpticalSizing );
+ m_aSub[SwFontScript::CTL].SetOpticalSizing( bOpticalSizing );
+}
+
inline void SwFont::SetPropWidth( const sal_uInt16 nNew )
{
if( nNew != m_aSub[SwFontScript::Latin].GetPropWidth() )
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index f28276de6c93..b3afcb4999cd 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -2622,6 +2622,7 @@ void SwContentFrame::UpdateAttr_( const SfxPoolItem*
pOld, const SfxPoolItem* pN
case RES_CHRATR_ESCAPEMENT:
case RES_CHRATR_CONTOUR:
case RES_CHRATR_NOHYPHEN:
+ case RES_CHRATR_OPTICAL_SIZING:
case RES_PARATR_NUMRULE:
rInvFlags |= SwContentFrameInvFlags::SetCompletePaint;
break;
diff --git a/sw/source/core/text/atrhndl.hxx b/sw/source/core/text/atrhndl.hxx
index 979b99800124..f4ebc728ce7d 100644
--- a/sw/source/core/text/atrhndl.hxx
+++ b/sw/source/core/text/atrhndl.hxx
@@ -18,7 +18,7 @@
*/
#pragma once
-#define NUM_ATTRIBUTE_STACKS 46
+#define NUM_ATTRIBUTE_STACKS 47
#include <vector>
#include <swfntcch.hxx>
diff --git a/sw/source/core/text/atrstck.cxx b/sw/source/core/text/atrstck.cxx
index 1d8c0ba479f5..caf108486f09 100644
--- a/sw/source/core/text/atrstck.cxx
+++ b/sw/source/core/text/atrstck.cxx
@@ -44,6 +44,7 @@
#include <editeng/boxitem.hxx>
#include <editeng/nhypitem.hxx>
#include <editeng/shaditem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <viewopt.hxx>
#include <charfmt.hxx>
#include <fchrfmt.hxx>
@@ -115,18 +116,19 @@ const sal_uInt8 StackPos[ RES_TXTATR_WITHEND_END -
RES_CHRATR_BEGIN + 1 ] =
0, // RES_CHRATR_GRABBAG, // 43
0, // RES_CHRATR_BIDIRTL, // 44
0, // RES_CHRATR_UNUSED3, // 45
- 39, // RES_CHRATR_SCRIPT_HINT, // 46
- 40, // RES_TXTATR_REFMARK, // 47
- 41, // RES_TXTATR_TOXMARK, // 48
- 42, // RES_TXTATR_META, // 49
- 42, // RES_TXTATR_METAFIELD, // 50
+ 39, // RES_CHRATR_SCRIPT_HINT, // 45
+ 40, // RES_CHRATR_OPTICAL_SIZING // 46
+ 41, // RES_TXTATR_REFMARK, // 47
+ 42, // RES_TXTATR_TOXMARK, // 48
+ 43, // RES_TXTATR_META, // 49
+ 43, // RES_TXTATR_METAFIELD, // 50
0, // RES_TXTATR_AUTOFMT, // 51
0, // RES_TXTATR_INETFMT // 52
0, // RES_TXTATR_CHARFMT, // 53
- 43, // RES_TXTATR_CJK_RUBY, // 54
+ 44, // RES_TXTATR_CJK_RUBY, // 54
0, // RES_TXTATR_UNKNOWN_CONTAINER, // 55
- 44, // RES_TXTATR_INPUTFIELD // 56
- 45, // RES_TXTATR_CONTENTCONTROL // 57
+ 45, // RES_TXTATR_INPUTFIELD // 56
+ 46, // RES_TXTATR_CONTENTCONTROL // 57
};
namespace CharFormat
@@ -831,6 +833,9 @@ void SwAttrHandler::FontChg(const SfxPoolItem& rItem,
SwFont& rFnt, bool bPush )
rFnt.SetVertical(m_pDefaultArray[ nRotateStack
]->StaticWhichCast(RES_CHRATR_ROTATE).GetValue(), m_bVertLayout);
break;
}
+ case RES_CHRATR_OPTICAL_SIZING :
+ rFnt.SetOpticalSizing(
rItem.StaticWhichCast(RES_CHRATR_OPTICAL_SIZING).GetValue() );
+ break;
case RES_TXTATR_CJK_RUBY :
rFnt.SetVertical( 0_deg10, m_bVertLayout );
break;
diff --git a/sw/source/core/txtnode/swfont.cxx
b/sw/source/core/txtnode/swfont.cxx
index ef33a4e6bae8..e7cc710827af 100644
--- a/sw/source/core/txtnode/swfont.cxx
+++ b/sw/source/core/txtnode/swfont.cxx
@@ -665,6 +665,8 @@ void SwFont::SetDiffFnt( const SfxItemSet *pAttrSet,
const SvxTwoLinesItem* pTwoLinesItem = pAttrSet->GetItemIfSet(
RES_CHRATR_TWO_LINES );
if( pTwoLinesItem && pTwoLinesItem->GetValue() )
SetVertical( 0_deg10 );
+ if( const SvxOpticalSizingItem* pItem = pAttrSet->GetItemIfSet(
RES_CHRATR_OPTICAL_SIZING ) )
+ SetOpticalSizing( pItem->GetValue() );
}
else
{
@@ -854,6 +856,7 @@ SwFont::SwFont( const SwAttrSet* pAttrSet,
m_aSub[ SwFontScript::CJK ].m_bSmallCapsPercentage66 = true;
m_aSub[ SwFontScript::CTL ].m_bSmallCapsPercentage66 = true;
}
+ SetOpticalSizing( pAttrSet->GetOpticalSizing().GetValue() );
}
SwFont::~SwFont()
diff --git a/sw/source/core/unocore/unomap1.cxx
b/sw/source/core/unocore/unomap1.cxx
index 184c46aafb98..d73181f1157a 100644
--- a/sw/source/core/unocore/unomap1.cxx
+++ b/sw/source/core/unocore/unomap1.cxx
@@ -206,6 +206,7 @@ std::span<const SfxItemPropertyMapEntry>
SwUnoPropertyMapProvider::GetCharStyleP
{ UNO_NAME_CHAR_OVERLINE_HAS_COLOR, RES_CHRATR_OVERLINE ,
cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TL_HASCOLOR},
{ UNO_NAME_CHAR_KERNING, RES_CHRATR_KERNING ,
cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, CONVERT_TWIPS},
{ UNO_NAME_CHAR_NO_HYPHENATION, RES_CHRATR_NOHYPHEN ,
cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},
+ { UNO_NAME_CHAR_OPTICAL_SIZING, RES_CHRATR_OPTICAL_SIZING ,
cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},
{ UNO_NAME_CHAR_SHADOWED, RES_CHRATR_SHADOWED ,
cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},
{ UNO_NAME_CHAR_CONTOURED, RES_CHRATR_CONTOUR,
cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},
{ UNO_NAME_CHAR_WORD_MODE,
RES_CHRATR_WORDLINEMODE,cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},
@@ -278,6 +279,7 @@ std::span<const SfxItemPropertyMapEntry>
SwUnoPropertyMapProvider::GetAutoCharS
{ UNO_NAME_CHAR_OVERLINE_HAS_COLOR, RES_CHRATR_OVERLINE ,
cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TL_HASCOLOR},
{ UNO_NAME_CHAR_KERNING, RES_CHRATR_KERNING ,
cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, CONVERT_TWIPS},
{ UNO_NAME_CHAR_NO_HYPHENATION, RES_CHRATR_NOHYPHEN ,
cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},
+ { UNO_NAME_CHAR_OPTICAL_SIZING, RES_CHRATR_OPTICAL_SIZING ,
cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},
{ UNO_NAME_CHAR_SHADOWED, RES_CHRATR_SHADOWED ,
cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},
{ UNO_NAME_CHAR_CONTOURED, RES_CHRATR_CONTOUR,
cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},
{ UNO_NAME_CHAR_WORD_MODE,
RES_CHRATR_WORDLINEMODE,cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},
diff --git a/sw/source/core/unocore/unomapproperties.hxx
b/sw/source/core/unocore/unomapproperties.hxx
index 62fa63945d35..015c08af042b 100644
--- a/sw/source/core/unocore/unomapproperties.hxx
+++ b/sw/source/core/unocore/unomapproperties.hxx
@@ -172,6 +172,7 @@
CTL_FONT_PROPERTIES \
{ UNO_NAME_CHAR_KERNING, RES_CHRATR_KERNING,
cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID,
CONVERT_TWIPS }, \
{ UNO_NAME_CHAR_NO_HYPHENATION, RES_CHRATR_NOHYPHEN,
cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0
}, \
+ { UNO_NAME_CHAR_OPTICAL_SIZING,
RES_CHRATR_OPTICAL_SIZING, cppu::UnoType<bool>::get(),
PropertyAttribute::MAYBEVOID, 0 }, \
{ UNO_NAME_CHAR_SHADOWED, RES_CHRATR_SHADOWED,
cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0
}, \
{ UNO_NAME_CHAR_CONTOURED, RES_CHRATR_CONTOUR,
cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0
}, \
{ UNO_NAME_DROP_CAP_FORMAT, RES_PARATR_DROP,
cppu::UnoType<css::style::DropCapFormat>::get(),
PropertyAttribute::MAYBEVOID, MID_DROPCAP_FORMAT | CONVERT_TWIPS }, \
@@ -446,6 +447,7 @@
{ UNO_NAME_PARA_FIRST_LINE_INDENT_RELATIVE,
RES_MARGIN_FIRSTLINE, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE,
MID_FIRST_LINE_REL_INDENT|CONVERT_TWIPS},\
{ UNO_NAME_CHAR_KERNING, RES_CHRATR_KERNING ,
cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, CONVERT_TWIPS},\
{ UNO_NAME_CHAR_NO_HYPHENATION, RES_CHRATR_NOHYPHEN ,
cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\
+ { UNO_NAME_CHAR_OPTICAL_SIZING, RES_CHRATR_OPTICAL_SIZING
, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\
{ UNO_NAME_CHAR_SHADOWED, RES_CHRATR_SHADOWED ,
cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\
{ UNO_NAME_CHAR_CONTOURED, RES_CHRATR_CONTOUR,
cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\
{ UNO_NAME_DROP_CAP_FORMAT, RES_PARATR_DROP,
cppu::UnoType<css::style::DropCapFormat>::get() , PROPERTY_NONE,
MID_DROPCAP_FORMAT|CONVERT_TWIPS },\
diff --git a/sw/source/filter/html/css1atr.cxx
b/sw/source/filter/html/css1atr.cxx
index 42e884c1b2eb..6f80bb53ff47 100644
--- a/sw/source/filter/html/css1atr.cxx
+++ b/sw/source/filter/html/css1atr.cxx
@@ -3465,6 +3465,7 @@ SwAttrFnTab const aCSS1AttrFnTab = {
/* RES_CHRATR_BIDIRTL */ nullptr,
/* RES_CHRATR_UNUSED3 */ nullptr,
/* RES_CHRATR_SCRIPT_HINT */ nullptr,
+/* RES_CHRATR_OPTICAL_SIZING */ nullptr,
/* RES_TXTATR_REFMARK */ nullptr,
/* RES_TXTATR_TOXMARK */ nullptr,
diff --git a/sw/source/filter/html/htmlatr.cxx
b/sw/source/filter/html/htmlatr.cxx
index 1a5076dc1fa3..d917fea69094 100644
--- a/sw/source/filter/html/htmlatr.cxx
+++ b/sw/source/filter/html/htmlatr.cxx
@@ -3316,6 +3316,7 @@ const SwAttrFnTab aHTMLAttrFnTab = {
/* RES_CHRATR_BIDIRTL */ nullptr,
/* RES_CHRATR_UNUSED3 */ nullptr,
/* RES_CHRATR_SCRIPT_HINT */ nullptr,
+/* RES_CHRATR_OPTICAL_SIZING */ nullptr,
/* RES_TXTATR_REFMARK */ nullptr,
/* RES_TXTATR_TOXMARK */ nullptr,
diff --git a/sw/source/filter/ww8/attributeoutputbase.hxx
b/sw/source/filter/ww8/attributeoutputbase.hxx
index 2d46bef3842b..2f4000819959 100644
--- a/sw/source/filter/ww8/attributeoutputbase.hxx
+++ b/sw/source/filter/ww8/attributeoutputbase.hxx
@@ -48,6 +48,7 @@ class SvxShadowedItem;
class SvxUnderlineItem;
class SvxWeightItem;
class SvxAutoKernItem;
+class SvxOpticalSizingItem;
class SvxBlinkItem;
class SvxBrushItem;
class XFillStyleItem;
@@ -399,6 +400,9 @@ protected:
/// Sfx item RES_CHRATR_AUTOKERN
virtual void CharAutoKern( const SvxAutoKernItem& ) = 0;
+ /// Sfx item RES_CHRATR_OPTICAL_SIZING
+ virtual void CharOpticalSizing( const SvxOpticalSizingItem& ) = 0;
+
/// Sfx item RES_CHRATR_BLINK
virtual void CharAnimatedText( const SvxBlinkItem& ) = 0;
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 8d4b05c44265..02033dd52f12 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -56,6 +56,7 @@
#include <oox/export/drawingml.hxx>
#include <editeng/autokernitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <editeng/unoprnms.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/tstpitem.hxx>
@@ -5259,6 +5260,9 @@ void DocxAttributeOutput::OutputDefaultItem(const
SfxPoolItem& rHt)
case RES_CHRATR_AUTOKERN:
bMustWrite = rHt.StaticWhichCast(RES_CHRATR_AUTOKERN).GetValue();
break;
+ case RES_CHRATR_OPTICAL_SIZING:
+ bMustWrite =
rHt.StaticWhichCast(RES_CHRATR_OPTICAL_SIZING).GetValue();
+ break;
case RES_CHRATR_BLINK:
bMustWrite = rHt.StaticWhichCast(RES_CHRATR_BLINK).GetValue();
break;
@@ -8396,6 +8400,11 @@ void DocxAttributeOutput::CharAutoKern( const
SvxAutoKernItem& rAutoKern )
m_pSerializer->singleElementNS(XML_w, XML_kern, FSNS(XML_w, XML_val),
sFontSize);
}
+void DocxAttributeOutput::CharOpticalSizing( const SvxOpticalSizingItem& )
+{
+ // MSOffice has no equivalent for optical sizing, so nothing is exported.
+}
+
void DocxAttributeOutput::CharAnimatedText( const SvxBlinkItem& rBlink )
{
if ( rBlink.GetValue() )
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx
b/sw/source/filter/ww8/docxattributeoutput.hxx
index ca9db3e30ece..45d6052766ab 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -586,6 +586,9 @@ protected:
/// Sfx item RES_CHRATR_AUTOKERN
virtual void CharAutoKern( const SvxAutoKernItem& ) override;
+ /// Sfx item RES_CHRATR_OPTICAL_SIZING
+ virtual void CharOpticalSizing( const SvxOpticalSizingItem& ) override;
+
/// Sfx item RES_CHRATR_BLINK
virtual void CharAnimatedText( const SvxBlinkItem& rBlink ) override;
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx
b/sw/source/filter/ww8/rtfattributeoutput.cxx
index e4051aa159f9..9e1c91879c31 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -49,6 +49,7 @@
#include <editeng/contouritem.hxx>
#include <editeng/shdditem.hxx>
#include <editeng/autokernitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <editeng/emphasismarkitem.hxx>
#include <editeng/twolinesitem.hxx>
#include <editeng/charscaleitem.hxx>
@@ -516,6 +517,9 @@ void RtfAttributeOutput::OutputFormattingItem(const
SfxPoolItem& item, OStringBu
case RES_CHRATR_AUTOKERN:
OutputCharAutoKern(item.StaticWhichCast(RES_CHRATR_AUTOKERN), buf);
break;
+ case RES_CHRATR_OPTICAL_SIZING:
+
OutputCharOpticalSizing(item.StaticWhichCast(RES_CHRATR_OPTICAL_SIZING), buf);
+ break;
case RES_CHRATR_BLINK:
OutputCharAnimatedText(item.StaticWhichCast(RES_CHRATR_BLINK),
buf);
break;
@@ -3205,12 +3209,22 @@ void RtfAttributeOutput::CharAutoKern(const
SvxAutoKernItem& rAutoKern)
m_aCharFormatting.Put(rAutoKern);
}
+void RtfAttributeOutput::CharOpticalSizing(const SvxOpticalSizingItem&
rOpticalSizing)
+{
+ m_aCharFormatting.Put(rOpticalSizing);
+}
+
void RtfAttributeOutput::OutputCharAutoKern(const SvxAutoKernItem& rAutoKern,
OStringBuffer& buf)
{
buf.append(OOO_STRING_SVTOOLS_RTF_KERNING);
buf.append(static_cast<sal_Int32>(rAutoKern.GetValue() ? 1 : 0));
}
+void RtfAttributeOutput::OutputCharOpticalSizing(const SvxOpticalSizingItem&,
OStringBuffer&)
+{
+ // MSOffice has no equivalent for optical sizing, so nothing is exported.
+}
+
void RtfAttributeOutput::CharAnimatedText(const SvxBlinkItem& rBlink)
{
m_aCharFormatting.Put(rBlink);
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx
b/sw/source/filter/ww8/rtfattributeoutput.hxx
index 289773a1477d..8d6aeabe2c5c 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -301,6 +301,9 @@ protected:
/// Sfx item RES_CHRATR_AUTOKERN
void CharAutoKern(const SvxAutoKernItem& rAutoKern) override;
+ /// Sfx item RES_CHRATR_OPTICAL_SIZING
+ void CharOpticalSizing(const SvxOpticalSizingItem& rOpticalSizing)
override;
+
/// Sfx item RES_CHRATR_BLINK
void CharAnimatedText(const SvxBlinkItem& rBlink) override;
@@ -554,6 +557,8 @@ private:
bool assoc) const;
static void OutputCharWeightAssoc(const SvxWeightItem& rWeight,
OStringBuffer& buf, bool assoc);
static void OutputCharAutoKern(const SvxAutoKernItem& rAutoKern,
OStringBuffer& buf);
+ static void OutputCharOpticalSizing(const SvxOpticalSizingItem&
rOpticalSizing,
+ OStringBuffer& buf);
static void OutputCharAnimatedText(const SvxBlinkItem& rBlink,
OStringBuffer& buf);
void OutputCharBackground(const SvxBrushItem& rBrush, OStringBuffer& buf)
const;
static void OutputCharRotate(const SvxCharRotateItem& rRotate,
OStringBuffer& buf);
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index 12d10022332a..414555bf6525 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -64,6 +64,7 @@
#include <editeng/contouritem.hxx>
#include <editeng/shdditem.hxx>
#include <editeng/autokernitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <editeng/pbinitem.hxx>
#include <editeng/emphasismarkitem.hxx>
#include <editeng/twolinesitem.hxx>
@@ -1316,6 +1317,11 @@ void WW8AttributeOutput::CharAutoKern( const
SvxAutoKernItem& rAutoKern )
m_rWW8Export.InsUInt16( rAutoKern.GetValue() ? 2 : 0 );
}
+void WW8AttributeOutput::CharOpticalSizing( const SvxOpticalSizingItem& )
+{
+ // MSOffice has no equivalent for optical sizing, so nothing is exported.
+}
+
void WW8AttributeOutput::CharAnimatedText( const SvxBlinkItem& rBlink )
{
m_rWW8Export.InsUInt16( NS_sprm::CSfxText::val );
@@ -5763,6 +5769,9 @@ void AttributeOutputBase::OutputItem( const SfxPoolItem&
rHt )
case RES_CHRATR_AUTOKERN:
CharAutoKern(rHt.StaticWhichCast(RES_CHRATR_AUTOKERN));
break;
+ case RES_CHRATR_OPTICAL_SIZING:
+ CharOpticalSizing(rHt.StaticWhichCast(RES_CHRATR_OPTICAL_SIZING));
+ break;
case RES_CHRATR_BLINK:
CharAnimatedText(rHt.StaticWhichCast(RES_CHRATR_BLINK));
break;
diff --git a/sw/source/filter/ww8/ww8attributeoutput.hxx
b/sw/source/filter/ww8/ww8attributeoutput.hxx
index 501959b546d7..7c1ef75cdd06 100644
--- a/sw/source/filter/ww8/ww8attributeoutput.hxx
+++ b/sw/source/filter/ww8/ww8attributeoutput.hxx
@@ -252,6 +252,9 @@ protected:
/// Sfx item RES_CHRATR_AUTOKERN
virtual void CharAutoKern( const SvxAutoKernItem& ) override;
+ /// Sfx item RES_CHRATR_OPTICAL_SIZING
+ virtual void CharOpticalSizing( const SvxOpticalSizingItem& ) override;
+
/// Sfx item RES_CHRATR_BLINK
virtual void CharAnimatedText( const SvxBlinkItem& ) override;
diff --git a/sw/source/uibase/app/docshini.cxx
b/sw/source/uibase/app/docshini.cxx
index 4c24c8706c9c..f7a19b3e72e5 100644
--- a/sw/source/uibase/app/docshini.cxx
+++ b/sw/source/uibase/app/docshini.cxx
@@ -47,6 +47,7 @@
#include <editeng/orphitem.hxx>
#include <editeng/widwitem.hxx>
#include <editeng/hyphenzoneitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <vcl/metric.hxx>
#include <vcl/rendercontext/GetDefaultFontFlags.hxx>
#include <vcl/svapp.hxx>
@@ -302,6 +303,9 @@ bool SwDocShell::InitNew( const uno::Reference <
embed::XStorage >& xStor )
//#i16874# AutoKerning as default for new documents
m_xDoc->SetDefault( SvxAutoKernItem( true, RES_CHRATR_AUTOKERN ) );
+ // tdf#153368 Optical sizing as default for new documents
+ m_xDoc->SetDefault( SvxOpticalSizingItem( true, RES_CHRATR_OPTICAL_SIZING
) );
+
// #i42080# - Due to the several calls of method <SetDefault(..)>
// at the document instance, the document is modified. Thus, reset this
// status here. Note: In method <SubInitNew()> this is also done.
diff --git a/vcl/qa/cppunit/pdfexport/data/testOpticalSizing.odt
b/vcl/qa/cppunit/pdfexport/data/testOpticalSizing.odt
new file mode 100644
index 000000000000..cb9130423caa
Binary files /dev/null and
b/vcl/qa/cppunit/pdfexport/data/testOpticalSizing.odt differ
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index cc42c417c5b5..71ee4c282fc9 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -2167,6 +2167,45 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest,
testVariableFontPSName2)
#endif
}
+// This test docuemnt embeds a variable font with opsz axis, and sets the text
in the same font but
+// different point sizes. The font should be embedded multiple times as
different instances
+// corresponding to the different opsz values.
+CPPUNIT_TEST_FIXTURE(PdfExportTest, testOpticalSizing)
+{
+// Embedding variable fonts does not work on Linux, only the default instance
is enumerated
+// https://bugs.documentfoundation.org/show_bug.cgi?id=155853
+#if defined MACOSX || defined _WIN32
+ loadFromFile(u"testOpticalSizing.odt");
+ save(TestFilter::PDF_WRITER);
+
+ vcl::filter::PDFDocument aDocument;
+ SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ);
+ CPPUNIT_ASSERT(aDocument.Read(aStream));
+
+ std::set<OString> aFontNames;
+ for (const auto& aElement : aDocument.GetElements())
+ {
+ auto pObject =
dynamic_cast<vcl::filter::PDFObjectElement*>(aElement.get());
+ if (!pObject)
+ continue;
+ auto pType =
dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type"_ostr));
+ if (pType && pType->GetValue() == "Font")
+ {
+ auto pName
+ =
dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("BaseFont"_ostr));
+ aFontNames.insert(pName->GetValue().copy(7)); // skip the subset id
+ }
+ }
+
+ std::set<OString> aExpected{ "Fraunces_150opsz_400wght"_ostr,
"Fraunces_144opsz_400wght"_ostr,
+ "Fraunces_80opsz_400wght"_ostr,
"Fraunces_60opsz_400wght"_ostr,
+ "Fraunces_40opsz_400wght"_ostr,
"Fraunces_20opsz_400wght"_ostr,
+ "Fraunces_6opsz_400wght"_ostr,
"Fraunces-Regular"_ostr };
+
+ CPPUNIT_ASSERT_EQUAL(aExpected, aFontNames);
+#endif
+}
+
CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf157679)
{
// Import the bugdoc and export as PDF.
commit bbd7f40dd83968093f2e80b5add338d38886ac43
Author: Khaled Hosny <[email protected]>
AuthorDate: Thu Feb 26 14:10:59 2026 +0200
Commit: Khaled Hosny <[email protected]>
CommitDate: Sun Mar 1 18:32:50 2026 +0200
tdf#153368: Support optical size for variable fonts, part 3
Add loext:font-optical-sizing attribute with two values, "auto" and
"none", modeled after CSS font-optical-sizing:
https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/font-optical-sizing
Change-Id: I05396f084dc81d0a797be0e7c0cd57991a6876e3
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index 18d855cb5a6d..79e096c4c2b2 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -877,6 +877,7 @@ namespace xmloff::token {
XML_FONT_NAME,
XML_FONT_NAME_ASIAN,
XML_FONT_NAME_COMPLEX,
+ XML_FONT_OPTICAL_SIZING,
XML_FONT_PITCH,
XML_FONT_PITCH_ASIAN,
XML_FONT_PITCH_COMPLEX,
diff --git a/include/xmloff/xmltypes.hxx b/include/xmloff/xmltypes.hxx
index 69b00fa035c8..e734251d0a84 100644
--- a/include/xmloff/xmltypes.hxx
+++ b/include/xmloff/xmltypes.hxx
@@ -303,6 +303,8 @@
#define XML_TYPE_TEXT_SCRIPT_TYPE (XML_TEXT_TYPES_START + 134)
+#define XML_TYPE_TEXT_FONT_OPTICAL_SIZING (XML_TEXT_TYPES_START + 135)
+
#endif // INCLUDED_XMLOFF_XMLTYPES_HXX
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng
b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng
index a3c7eb909c84..5faa53a792af 100644
--- a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng
+++ b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng
@@ -4009,6 +4009,18 @@
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
</rng:optional>
</rng:define>
+ <!-- TODO no proposal -->
+ <rng:define name="style-text-properties-attlist" combine="interleave">
+ <rng:optional>
+ <rng:attribute name="loext:font-optical-sizing">
+ <rng:choice>
+ <rng:value>auto</rng:value>
+ <rng:value>none</rng:value>
+ </rng:choice>
+ </rng:attribute>
+ </rng:optional>
+ </rng:define>
+
<!-- TODO no proposal -->
<rng:define name="style-graphic-properties-elements" combine="interleave">
<rng:optional>
diff --git a/xmloff/inc/xmlprop.hxx b/xmloff/inc/xmlprop.hxx
index c63ec8b44414..c73d8372f691 100644
--- a/xmloff/inc/xmlprop.hxx
+++ b/xmloff/inc/xmlprop.hxx
@@ -98,6 +98,7 @@ inline constexpr OUString PROP_CharLocale =
u"CharLocale"_ustr;
inline constexpr OUString PROP_CharLocaleAsian = u"CharLocaleAsian"_ustr;
inline constexpr OUString PROP_CharLocaleComplex = u"CharLocaleComplex"_ustr;
inline constexpr OUString PROP_CharNoHyphenation = u"CharNoHyphenation"_ustr;
+inline constexpr OUString PROP_CharOpticalSizing = u"CharOpticalSizing"_ustr;
inline constexpr OUString PROP_CharOverline = u"CharOverline"_ustr;
inline constexpr OUString PROP_CharOverlineColor = u"CharOverlineColor"_ustr;
inline constexpr OUString PROP_CharOverlineHasColor =
u"CharOverlineHasColor"_ustr;
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index a6b9c680eb3a..d904495e4fb5 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -889,6 +889,7 @@ namespace xmloff::token {
TOKEN( "font-name", XML_FONT_NAME ),
TOKEN( "font-name-asian", XML_FONT_NAME_ASIAN ),
TOKEN( "font-name-complex", XML_FONT_NAME_COMPLEX ),
+ TOKEN( "font-optical-sizing", XML_FONT_OPTICAL_SIZING ),
TOKEN( "font-pitch", XML_FONT_PITCH ),
TOKEN( "font-pitch-asian", XML_FONT_PITCH_ASIAN ),
TOKEN( "font-pitch-complex", XML_FONT_PITCH_COMPLEX ),
diff --git a/xmloff/source/text/txtprhdl.cxx b/xmloff/source/text/txtprhdl.cxx
index 7c02820dd5ed..c411fa5be5e3 100644
--- a/xmloff/source/text/txtprhdl.cxx
+++ b/xmloff/source/text/txtprhdl.cxx
@@ -1393,6 +1393,10 @@ static const XMLPropertyHandler *GetPropertyHandler
case XML_TYPE_TEXT_FONT_RELIEF:
pHdl = new XMLConstantsPropertyHandler( pXML_FontRelief_Enum,
XML_TOKEN_INVALID );
break;
+ case XML_TYPE_TEXT_FONT_OPTICAL_SIZING:
+ pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_AUTO ),
+ GetXMLToken( XML_NONE ) );
+ break;
case XML_TYPE_TEXT_ROTATION_ANGLE:
pHdl = new XMLTextRotationAnglePropHdl_Impl;
break;
diff --git a/xmloff/source/text/txtprmap.cxx b/xmloff/source/text/txtprmap.cxx
index 0374aa514644..7aaeba0f6aa6 100644
--- a/xmloff/source/text/txtprmap.cxx
+++ b/xmloff/source/text/txtprmap.cxx
@@ -253,6 +253,7 @@ XMLPropertyMapEntry constexpr aXMLParaPropMap[] =
MT_E( PROP_CharScaleWidth, XML_NAMESPACE_STYLE, XML_TEXT_SCALE,
XML_TYPE_PERCENT16, 0 ),
//RES_CHRATR_RELIEF
MT_E( PROP_CharRelief, XML_NAMESPACE_STYLE, XML_FONT_RELIEF,
XML_TYPE_TEXT_FONT_RELIEF, 0 ),
+ MAP_EXT( PROP_CharOpticalSizing, XML_NAMESPACE_LO_EXT,
XML_FONT_OPTICAL_SIZING, XML_TYPE_TEXT_FONT_OPTICAL_SIZING |
XML_TYPE_PROP_TEXT, 0 ),
// RES_CHRATR_HIDDEN
MT_E( PROP_CharHidden, XML_NAMESPACE_TEXT, XML_DISPLAY,
XML_TYPE_TEXT_HIDDEN_AS_DISPLAY|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_TEXT_DISPLAY
),
// RES_CHRATR_OVERLINE
@@ -639,6 +640,7 @@ XMLPropertyMapEntry constexpr aXMLTextPropMap[] =
MT_E( PROP_, XML_NAMESPACE_STYLE, XML_TEXT_COMBINE,
XML_TYPE_TEXT_COMBINE_CHARACTERS|MID_FLAG_NO_PROPERTY,
CTF_COMBINED_CHARACTERS_FIELD ),
//RES_CHRATR_RELIEF
MT_E( PROP_CharRelief, XML_NAMESPACE_STYLE, XML_FONT_RELIEF,
XML_TYPE_TEXT_FONT_RELIEF, 0 ),
+ MAP_EXT( PROP_CharOpticalSizing, XML_NAMESPACE_LO_EXT,
XML_FONT_OPTICAL_SIZING, XML_TYPE_TEXT_FONT_OPTICAL_SIZING |
XML_TYPE_PROP_TEXT, 0 ),
// RES_CHRATR_HIDDEN
MT_E( PROP_CharHidden, XML_NAMESPACE_TEXT, XML_DISPLAY,
XML_TYPE_TEXT_HIDDEN_AS_DISPLAY|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_TEXT_DISPLAY
),
// RES_CHRATR_OVERLINE
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index f268760695f5..9735eea566c5 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -794,6 +794,7 @@ font-kerning
font-name
font-name-asian
font-name-complex
+font-optical-sizing
font-pitch
font-pitch-asian
font-pitch-complex
commit e1208fd626b36dec1127f6512b03381f2ed5fc1c
Author: Khaled Hosny <[email protected]>
AuthorDate: Thu Feb 26 14:10:42 2026 +0200
Commit: Khaled Hosny <[email protected]>
CommitDate: Sun Mar 1 18:32:50 2026 +0200
tdf#153368: Support optical size for variable fonts, part 2
Add SvxOpticalSizingItem and EditEngine plumbing. Mostly mindlessly
copying stuff here. Lets hope for the best.
Change-Id: Idf0b062ff955fa35bd04c8e69c103e15887932f5
diff --git a/editeng/inc/editattr.hxx b/editeng/inc/editattr.hxx
index 210684d90f7f..8f9d2aeba0a6 100644
--- a/editeng/inc/editattr.hxx
+++ b/editeng/inc/editattr.hxx
@@ -394,6 +394,16 @@ public:
};
+
+class EditCharAttribOpticalSizing final : public EditCharAttrib
+{
+public:
+ EditCharAttribOpticalSizing(SfxItemPool&, const SfxPoolItem&, sal_Int32
nStart, sal_Int32 nEnd);
+
+ virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ) override;
+};
+
+
class EditCharAttribGrabBag final : public EditCharAttrib
{
public:
diff --git a/editeng/source/editeng/editattr.cxx
b/editeng/source/editeng/editattr.cxx
index 06ac807367af..e657acfff90b 100644
--- a/editeng/source/editeng/editattr.cxx
+++ b/editeng/source/editeng/editattr.cxx
@@ -39,6 +39,7 @@
#include <editeng/emphasismarkitem.hxx>
#include <editeng/charreliefitem.hxx>
#include <editeng/cmapitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <editattr.hxx>
@@ -465,6 +466,19 @@ void EditCharAttribRelief::SetFont( SvxFont& rFont,
OutputDevice* )
}
+
+EditCharAttribOpticalSizing::EditCharAttribOpticalSizing(SfxItemPool& rPool,
const SfxPoolItem& rItem, sal_Int32 _nStart, sal_Int32 _nEnd)
+: EditCharAttrib(rPool, rItem, _nStart, _nEnd)
+{
+ assert(rItem.Which() == EE_CHAR_OPTICALSIZING);
+}
+
+void EditCharAttribOpticalSizing::SetFont( SvxFont& rFont, OutputDevice* )
+{
+ rFont.SetOpticalSizing( static_cast<const
SvxOpticalSizingItem*>(GetItem())->GetValue() );
+}
+
+
EditCharAttribGrabBag::EditCharAttribGrabBag(SfxItemPool& rPool, const
SfxPoolItem& rItem, sal_Int32 _nStart, sal_Int32 _nEnd)
: EditCharAttrib(rPool, rItem, _nStart, _nEnd)
{
diff --git a/editeng/source/editeng/editdoc.cxx
b/editeng/source/editeng/editdoc.cxx
index 5b88a6095575..8112243c9f5c 100644
--- a/editeng/source/editeng/editdoc.cxx
+++ b/editeng/source/editeng/editdoc.cxx
@@ -45,6 +45,7 @@
#include <editeng/lrspitem.hxx>
#include <editeng/ulspitem.hxx>
#include <editeng/lspcitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#if ENABLE_YRS
#include <editeng/frmdiritem.hxx>
#include <editeng/hngpnctitem.hxx>
@@ -321,6 +322,11 @@ EditCharAttrib* MakeCharAttrib( SfxItemPool& rPool, const
SfxPoolItem& rAttr, sa
return new EditCharAttribScriptHint(rPool, rAttr, nS, nE);
}
break;
+ case EE_CHAR_OPTICALSIZING:
+ {
+ return new EditCharAttribOpticalSizing(rPool, rAttr, nS, nE );
+ }
+ break;
default:
break;
}
@@ -1224,7 +1230,13 @@ void YrsInsertAttribImplImpl(YrsWrite const& yw,
SfxPoolItem const& rItm,
// these aren't editable?
//constexpr TypedWhichId<SvXMLAttrContainerItem> EE_CHAR_XMLATTRIBS
(EE_CHAR_START+27);
//constexpr TypedWhichId<SfxGrabBagItem> EE_CHAR_GRABBAG
(EE_CHAR_START+30);
-
+ case EE_CHAR_OPTICALSIZING:
+ {
+ SvxOpticalSizingItem const& rItem{static_cast<SvxOpticalSizingItem
const&>(rItm)};
+ attr = yinput_bool(rItem.GetValue() ? Y_TRUE : Y_FALSE);
+ attrName = "EE_CHAR_OPTICALSIZING";
+ break;
+ }
default:
assert(false);
}
@@ -1581,6 +1593,8 @@ char const* YrsWhichToAttrName(sal_Int16 const nWhich)
return "EE_PARA_JUST_METHOD";
case EE_PARA_VER_JUST:
return "EE_PARA_VER_JUST";
+ case EE_CHAR_OPTICALSIZING:
+ return "EE_CHAR_OPTICALSIZING";
default:
assert(false);
abort();
@@ -1823,6 +1837,10 @@ void YrsImplInsertAttr(SfxItemSet & rSet,
::std::vector<sal_uInt16> *const pRemo
{
nWhich = EE_PARA_VER_JUST;
}
+ else if (strcmp(pKey, "EE_CHAR_OPTICALSIZING") == 0)
+ {
+ nWhich = EE_CHAR_OPTICALSIZING;
+ }
else if (pKey[0] == 'E' && pKey[1] == 'E' && pKey[2] == '_')
{
abort();
@@ -2454,6 +2472,13 @@ void YrsImplInsertAttr(SfxItemSet & rSet,
::std::vector<sal_uInt16> *const pRemo
rSet.Put(item);
break;
}
+ case EE_CHAR_OPTICALSIZING:
+ {
+ yvalidate(rValue.tag == Y_JSON_BOOL);
+ SvxOpticalSizingItem const item{rValue.value.flag == Y_TRUE,
nWhich};
+ rSet.Put(item);
+ break;
+ }
default:
assert(false);
@@ -3280,6 +3305,8 @@ void CreateFont( SvxFont& rFont, const SfxItemSet& rSet,
bool bSearchInParent, S
rFont.SetEmphasisMark( rSet.Get( EE_CHAR_EMPHASISMARK
).GetEmphasisMark() );
if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_RELIEF ) ==
SfxItemState::SET ) )
rFont.SetRelief( rSet.Get( EE_CHAR_RELIEF ).GetValue() );
+ if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OPTICALSIZING ) ==
SfxItemState::SET ) )
+ rFont.SetOpticalSizing( rSet.Get( EE_CHAR_OPTICALSIZING ).GetValue() );
// Operator == compares the individual members of the font if the impl
pointer is
// not equal. If all members are the same, this assignment makes
diff --git a/editeng/source/editeng/eerdll.cxx
b/editeng/source/editeng/eerdll.cxx
index c064110c136b..5c7069fe1174 100644
--- a/editeng/source/editeng/eerdll.cxx
+++ b/editeng/source/editeng/eerdll.cxx
@@ -67,6 +67,7 @@
#include <editeng/xmlcnitm.hxx>
#include <editeng/forbiddencharacterstable.hxx>
#include <editeng/justifyitem.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <tools/mapunit.hxx>
#include <tools/lazydelete.hxx>
#include <svl/itempool.hxx>
@@ -160,6 +161,7 @@ ItemInfoPackage& getItemInfoPackageEditEngine()
{ EE_CHAR_BKGCOLOR, new SvxColorItem( COL_AUTO, EE_CHAR_BKGCOLOR
), SID_ATTR_CHAR_BACK_COLOR, SFX_ITEMINFOFLAG_NONE },
{ EE_CHAR_RUBY, new SvxRubyItem( EE_CHAR_RUBY ),
SID_ATTR_CHAR_RUBY, SFX_ITEMINFOFLAG_NONE },
{ EE_CHAR_SCRIPT_HINT, new SvxScriptHintItem( EE_CHAR_SCRIPT_HINT
), SID_ATTR_CHAR_SCRIPT_HINT, SFX_ITEMINFOFLAG_NONE },
+ { EE_CHAR_OPTICALSIZING, new SvxOpticalSizingItem( false,
EE_CHAR_OPTICALSIZING ), SID_ATTR_CHAR_OPTICAL_SIZING, SFX_ITEMINFOFLAG_NONE },
{ EE_FEATURE_TAB, new SfxVoidItem( EE_FEATURE_TAB ), 0,
SFX_ITEMINFOFLAG_NONE },
{ EE_FEATURE_LINEBR, new SfxVoidItem( EE_FEATURE_LINEBR ), 0,
SFX_ITEMINFOFLAG_NONE },
{ EE_FEATURE_NOTCONV, new SvxColorItem( COL_RED,
EE_FEATURE_NOTCONV ), SID_ATTR_CHAR_CHARSETCOLOR, SFX_ITEMINFOFLAG_NONE },
diff --git a/editeng/source/items/textitem.cxx
b/editeng/source/items/textitem.cxx
index 0714418d99ab..49927a9868e8 100644
--- a/editeng/source/items/textitem.cxx
+++ b/editeng/source/items/textitem.cxx
@@ -82,6 +82,7 @@
#include <editeng/itemtype.hxx>
#include <editeng/scripthintitem.hxx>
#include <editeng/eerdll.hxx>
+#include <editeng/opticalsizingitem.hxx>
#include <docmodel/color/ComplexColorJSON.hxx>
#include <docmodel/uno/UnoComplexColor.hxx>
#include <docmodel/color/ComplexColor.hxx>
@@ -110,6 +111,7 @@ SfxPoolItem* SvxEmphasisMarkItem::CreateDefault() {return
new SvxEmphasisMarkIte
SfxPoolItem* SvxCharRotateItem::CreateDefault() {return new
SvxCharRotateItem(0_deg10, false, TypedWhichId<SvxCharRotateItem>(0));}
SfxPoolItem* SvxCharScaleWidthItem::CreateDefault() {return new
SvxCharScaleWidthItem(100, TypedWhichId<SvxCharScaleWidthItem>(0));}
SfxPoolItem* SvxCharReliefItem::CreateDefault() {return new
SvxCharReliefItem(FontRelief::NONE, 0);}
+SfxPoolItem* SvxOpticalSizingItem::CreateDefault() {return new
SvxOpticalSizingItem(false, 0);}
// class SvxFontListItem -------------------------------------------------
@@ -3023,4 +3025,32 @@ void SvxRsidItem::dumpAsXml(xmlTextWriterPtr pWriter)
const
(void)xmlTextWriterEndElement(pWriter);
}
+// class SvxOpticalSizingItem --------------------------------------------
+
+SvxOpticalSizingItem::SvxOpticalSizingItem( const bool bOpticalSizing, const
sal_uInt16 nId ) :
+ SfxBoolItem( nId, bOpticalSizing )
+{
+}
+
+SvxOpticalSizingItem* SvxOpticalSizingItem::Clone( SfxItemPool * ) const
+{
+ return new SvxOpticalSizingItem( *this );
+}
+
+bool SvxOpticalSizingItem::GetPresentation
+(
+ SfxItemPresentation /*ePres*/,
+ MapUnit /*eCoreUnit*/,
+ MapUnit /*ePresUnit*/,
+ OUString& rText, const IntlWrapper& /*rIntl*/
+) const
+{
+ TranslateId pId = RID_SVXITEMS_OPTICALSIZING_FALSE;
+
+ if ( GetValue() )
+ pId = RID_SVXITEMS_OPTICALSIZING_TRUE;
+ rText = EditResId(pId);
+ return true;
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/editeng/editids.hrc b/include/editeng/editids.hrc
index c431aeb6760f..d49d486b5e71 100644
--- a/include/editeng/editids.hrc
+++ b/include/editeng/editids.hrc
@@ -68,6 +68,7 @@ class SvxWidowsItem;
class SvxWordLineModeItem;
class SvxScriptHintItem;
class SvxFontListItem;
+class SvxOpticalSizingItem;
/*
These SID_SVX_START entries came from include/svx/svxids.hrc, avoid
@@ -188,6 +189,7 @@ class SvxFontListItem;
#define SID_ATTR_PARA_GRABBAG
TypedWhichId<SfxGrabBagItem>( SID_EDIT_START + 78 )
#define SID_ATTR_PARA_ADJUST_START ( SID_EDIT_START + 79 )
#define SID_ATTR_PARA_ADJUST_END ( SID_EDIT_START + 80 )
+#define SID_ATTR_CHAR_OPTICAL_SIZING
TypedWhichId<SvxOpticalSizingItem>( SID_EDIT_START + 81 )
#if 95 > (SID_EDIT_END-SID_EDIT_START)
diff --git a/include/editeng/editrids.hrc b/include/editeng/editrids.hrc
index 7990ae9a1e10..c39979a8f371 100644
--- a/include/editeng/editrids.hrc
+++ b/include/editeng/editrids.hrc
@@ -185,6 +185,8 @@
#define RID_SVXITEMS_BLINK_FALSE
NC_("RID_SVXITEMS_BLINK_FALSE", "Not Blinking")
#define RID_SVXITEMS_AUTOKERN_TRUE
NC_("RID_SVXITEMS_AUTOKERN_TRUE", "Pair Kerning")
#define RID_SVXITEMS_AUTOKERN_FALSE
NC_("RID_SVXITEMS_AUTOKERN_FALSE", "No pair kerning")
+#define RID_SVXITEMS_OPTICALSIZING_TRUE
NC_("RID_SVXITEMS_OPTICALSIZING_TRUE", "Optical Sizing")
+#define RID_SVXITEMS_OPTICALSIZING_FALSE
NC_("RID_SVXITEMS_OPTICALSIZING_FALSE", "No optical sizing")
#define RID_SVXITEMS_NOHYPHENATION_TRUE
NC_("RID_SVXITEMS_NOHYPHENATION_TRUE", "No hyphenation")
#define RID_SVXITEMS_WORDLINE_TRUE
NC_("RID_SVXITEMS_WORDLINE_TRUE", "Individual words")
#define RID_SVXITEMS_WORDLINE_FALSE
NC_("RID_SVXITEMS_WORDLINE_FALSE", "Not Words Only")
diff --git a/include/editeng/eeitem.hxx b/include/editeng/eeitem.hxx
index 89b85207a24a..f9ffe91fea14 100644
--- a/include/editeng/eeitem.hxx
+++ b/include/editeng/eeitem.hxx
@@ -63,6 +63,7 @@ class SvxJustifyMethodItem;
class SvxVerJustifyItem;
class SvxRubyItem;
class SvxScriptHintItem;
+class SvxOpticalSizingItem;
/*
* NOTE: Changes in this file will probably require
@@ -133,8 +134,9 @@ inline constexpr TypedWhichId<SfxGrabBagItem>
EE_CHAR_GRABBAG (EE
inline constexpr TypedWhichId<SvxColorItem> EE_CHAR_BKGCOLOR
(EE_CHAR_START+31);
inline constexpr TypedWhichId<SvxRubyItem> EE_CHAR_RUBY
(EE_CHAR_START+32);
inline constexpr TypedWhichId<SvxScriptHintItem> EE_CHAR_SCRIPT_HINT
(EE_CHAR_START+33);
+inline constexpr TypedWhichId<SvxOpticalSizingItem> EE_CHAR_OPTICALSIZING
(EE_CHAR_START+34);
-inline constexpr sal_uInt16 EE_CHAR_END
(EE_CHAR_START + 33);
+inline constexpr sal_uInt16 EE_CHAR_END
(EE_CHAR_START + 34);
inline constexpr sal_uInt16 EE_FEATURE_START (EE_CHAR_END + 1);
inline constexpr sal_uInt16 EE_FEATURE_TAB (EE_FEATURE_START + 0);
diff --git a/include/editeng/opticalsizingitem.hxx
b/include/editeng/opticalsizingitem.hxx
new file mode 100644
index 000000000000..7e1dca8f02ff
--- /dev/null
+++ b/include/editeng/opticalsizingitem.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4;
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <svl/eitem.hxx>
+#include <editeng/editengdllapi.h>
+
+// class SvxOpticalSizingItem ---------------------------------------------
+
+/*
+ [Description]
+ Attribute for Font Optical Sizing.
+*/
+
+class EDITENG_DLLPUBLIC SvxOpticalSizingItem final : public SfxBoolItem
+{
+public:
+ static SfxPoolItem* CreateDefault();
+ DECLARE_ITEM_TYPE_FUNCTION(SvxOpticalSizingItem)
+ SvxOpticalSizingItem(const bool bOpticalSizing /*= false*/, const
sal_uInt16 nId);
+
+ // "pure virtual Methods" from SfxPoolItem
+ virtual SvxOpticalSizingItem* Clone(SfxItemPool* pPool = nullptr) const
override;
+
+ virtual bool GetPresentation(SfxItemPresentation ePres, MapUnit
eCoreMetric,
+ MapUnit ePresMetric, OUString& rText,
+ const IntlWrapper&) const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s
cinkeys+=0=break: */
diff --git a/include/svl/poolitem.hxx b/include/svl/poolitem.hxx
index 69bc63eee3e1..ca5a55dd4450 100644
--- a/include/svl/poolitem.hxx
+++ b/include/svl/poolitem.hxx
@@ -311,6 +311,7 @@ enum class SfxItemType : sal_uInt16
SvxAdjustItemType,
SvxAutoFrameDirectionItemType,
SvxAutoKernItemType,
+ SvxOpticalSizingItemType,
SvxB3DVectorItemType,
SvxBitmapListItemType,
SvxBlinkItemType,
commit d623349edd7ab61998eeb1ec50aa5d876dd1c607
Author: Khaled Hosny <[email protected]>
AuthorDate: Thu Feb 26 14:10:17 2026 +0200
Commit: Khaled Hosny <[email protected]>
CommitDate: Sun Mar 1 18:32:50 2026 +0200
tdf#153368: Support optical size for variable fonts, part 1
Font plumbing to enable opsz axis and set it to font’s point size.
Change-Id: I3a4941591e47788dc659ba55d37c9f28d2f267d6
diff --git a/include/vcl/font.hxx b/include/vcl/font.hxx
index a7c1cc3c9659..2e4b20d5d037 100644
--- a/include/vcl/font.hxx
+++ b/include/vcl/font.hxx
@@ -137,6 +137,9 @@ public:
short GetFixKerning() const;
bool IsFixKerning() const;
+ void SetOpticalSizing( bool bOpticalSizing );
+ bool GetOpticalSizing() const;
+
void SetOutline( bool bOutline );
bool IsOutline() const;
void SetShadow( bool bShadow );
diff --git a/vcl/inc/font/FontSelectPattern.hxx
b/vcl/inc/font/FontSelectPattern.hxx
index 8655ec7c4106..9dae3b41b810 100644
--- a/vcl/inc/font/FontSelectPattern.hxx
+++ b/vcl/inc/font/FontSelectPattern.hxx
@@ -68,6 +68,7 @@ public:
LanguageType meLanguage; // text language
bool mbVertical; // vertical mode of requested
font
bool mbNonAntialiased; // true if antialiasing is
disabled
+ bool mbOpticalSizing; // true if optical sizing is
enabled
bool mbEmbolden; // Force emboldening
ItalicMatrix maItalicMatrix; // Force matrix for slant
diff --git a/vcl/inc/font/LogicalFontInstance.hxx
b/vcl/inc/font/LogicalFontInstance.hxx
index 34ce611685b6..a11ed8607910 100644
--- a/vcl/inc/font/LogicalFontInstance.hxx
+++ b/vcl/inc/font/LogicalFontInstance.hxx
@@ -108,6 +108,20 @@ public: // TODO: make data members private
}
const std::vector<hb_variation_t>& GetVariations() const;
+ void SetOpticalSizing(bool bOpticalSizing)
+ {
+ m_bOpticalSizing = bOpticalSizing;
+ mxVariations.reset();
+ }
+ bool GetOpticalSizing() const { return m_bOpticalSizing; }
+
+ void SetPointSize(float fPointSize)
+ {
+ m_fPointSize = fPointSize;
+ mxVariations.reset();
+ }
+ float GetPointSize() const { return m_fPointSize; }
+
const vcl::font::PhysicalFontFace* GetFontFace() const { return
m_pFontFace.get(); }
vcl::font::PhysicalFontFace* GetFontFace() { return m_pFontFace.get(); }
const ImplFontCache* GetFontCache() const { return mpFontCache; }
@@ -157,6 +171,8 @@ private:
std::optional<bool> m_xbIsGraphiteFont;
std::vector<hb_variation_t> m_aVariations;
mutable std::optional<std::vector<hb_variation_t>> mxVariations;
+ bool m_bOpticalSizing = false;
+ float m_fPointSize = 0;
mutable hb_draw_funcs_t* m_pHbDrawFuncs = nullptr;
basegfx::B2DPolygon m_aDrawPolygon;
diff --git a/vcl/inc/impfont.hxx b/vcl/inc/impfont.hxx
index 1e697b9ee3d1..0d04e2bc5447 100644
--- a/vcl/inc/impfont.hxx
+++ b/vcl/inc/impfont.hxx
@@ -128,7 +128,8 @@ private:
mbConfigLookup:1, // config lookup should only be
done once
mbShadow:1,
mbVertical:1,
- mbTransparent:1; // compatibility, now on output
device
+ mbTransparent:1, // compatibility, now on output
device
+ mbOpticalSizing:1;
// deprecated variables - device independent
Color maColor; // compatibility, now on output
device
diff --git a/vcl/qa/cppunit/complextext.cxx b/vcl/qa/cppunit/complextext.cxx
index 5b4e36ac88ca..68ba2359f3d0 100644
--- a/vcl/qa/cppunit/complextext.cxx
+++ b/vcl/qa/cppunit/complextext.cxx
@@ -24,6 +24,7 @@ static std::ostream& operator<<(std::ostream& rStream, const
std::vector<double>
#include <vcl/virdev.hxx>
// workaround MSVC2015 issue with std::unique_ptr
#include <sallayout.hxx>
+#include <tools/mapunit.hxx>
#if HAVE_MORE_FONTS
@@ -872,4 +873,53 @@ CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testTdf163761)
}
}
+// Load a variable font with opsz axis, and enable optical sizing.
+// In this particular font, at the two ends of the opsz axis, some characters
produce different
+// glyphs. So we check that the glyphs are different for different point sizes.
+CPPUNIT_TEST_FIXTURE(VclComplexTextTest, testOpticalSizing)
+{
+#if HAVE_MORE_FONTS
+ ScopedVclPtrInstance<VirtualDevice> pOutDev;
+ pOutDev->SetMapMode(MapMode(MapUnit::MapPoint));
+
+ bool bAdded = addFont(pOutDev, u"Fraunces-VariableFont_opsz,wght.ttf",
u"Fraunces");
+ CPPUNIT_ASSERT_EQUAL(true, bAdded);
+
+ auto aText = u"nh"_ustr;
+
+ // Test with small font size
+ vcl::Font aFont1{ u"Fraunces"_ustr, u"Regular"_ustr, Size{ 0, 9 } };
+ aFont1.SetOpticalSizing(true);
+ pOutDev->SetFont(aFont1);
+
+ auto pLayout1 = pOutDev->ImplLayout(aText, /*nIndex*/ 0, /*nLen*/
aText.getLength());
+
+ std::vector<sal_GlyphId> aGlyphs1;
+ const GlyphItem* pGlyph = nullptr;
+ basegfx::B2DPoint stPos;
+ int nCurrPos = 0;
+ while (pLayout1->GetNextGlyph(&pGlyph, stPos, nCurrPos))
+ aGlyphs1.push_back(pGlyph->glyphId());
+
+ // Test with large font size
+ vcl::Font aFont2{ u"Fraunces"_ustr, u"Regular"_ustr, Size{ 0, 144 } };
+ aFont2.SetOpticalSizing(true);
+ pOutDev->SetFont(aFont2);
+
+ auto pLayout2 = pOutDev->ImplLayout(aText, /*nIndex*/ 0, /*nLen*/
aText.getLength());
+
+ std::vector<sal_GlyphId> aGlyphs2;
+ pGlyph = nullptr;
+ nCurrPos = 0;
+ while (pLayout2->GetNextGlyph(&pGlyph, stPos, nCurrPos))
+ aGlyphs2.push_back(pGlyph->glyphId());
+
-e
... etc. - the rest is truncated