1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sfx2/dialoghelper.hxx>
21 #include <sfx2/viewsh.hxx>
22 #include <sfx2/printer.hxx>
23 #include <vcl/event.hxx>
24 #include <vcl/metric.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/settings.hxx>
27 #include <unicode/uchar.h>
28 #include <com/sun/star/uno/Reference.h>
29 #include <com/sun/star/i18n/BreakIterator.hpp>
30 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
31 #include <comphelper/processfactory.hxx>
32 
33 #include <com/sun/star/i18n/ScriptType.hpp>
34 
35 #include <vector>
36 #include <deque>
37 #include <svtools/colorcfg.hxx>
38 #include <svtools/sampletext.hxx>
39 
40 #include <svx/fntctrl.hxx>
41 #include <svx/svxids.hrc>
42 #include <svx/sdasitm.hxx>
43 
44 // Item set includes
45 #include <svl/itemset.hxx>
46 #include <svl/itempool.hxx>
47 #include <svl/stritem.hxx>
48 #include <svl/languageoptions.hxx>
49 
50 #include <editeng/colritem.hxx>
51 #include <editeng/fontitem.hxx>
52 #include <editeng/editids.hrc>
53 #include <editeng/postitem.hxx>
54 #include <editeng/udlnitem.hxx>
55 #include <editeng/crossedoutitem.hxx>
56 #include <editeng/contouritem.hxx>
57 #include <editeng/wghtitem.hxx>
58 #include <editeng/fhgtitem.hxx>
59 #include <editeng/shdditem.hxx>
60 #include <editeng/escapementitem.hxx>
61 #include <editeng/wrlmitem.hxx>
62 #include <editeng/cmapitem.hxx>
63 #include <editeng/kernitem.hxx>
64 #include <editeng/brushitem.hxx>
65 #include <editeng/emphasismarkitem.hxx>
66 #include <editeng/charreliefitem.hxx>
67 #include <editeng/twolinesitem.hxx>
68 #include <editeng/charscaleitem.hxx>
69 #include <editeng/langitem.hxx>
70 
71 //TODO: remove this and calculate off the actual size of text, not
72 //an arbitrary number of characters
73 #define TEXT_WIDTH 80
74 
75 using namespace ::com::sun::star::uno;
76 using namespace ::com::sun::star::lang;
77 using ::com::sun::star::i18n::XBreakIterator;
78 using ::com::sun::star::i18n::BreakIterator;
79 
80 
81 // small helper functions to set fonts
82 
83 namespace
84 {
scaleFontWidth(vcl::Font & rFont,vcl::RenderContext const & rRenderContext,long & n100PercentFont)85 void scaleFontWidth(vcl::Font& rFont, vcl::RenderContext const & rRenderContext,long& n100PercentFont)
86 {
87     rFont.SetAverageFontWidth(0);
88     n100PercentFont = rRenderContext.GetFontMetric(rFont).GetAverageFontWidth();
89 }
90 
initFont(vcl::Font & rFont)91 void initFont(vcl::Font& rFont)
92 {
93     rFont.SetTransparent(true);
94     rFont.SetAlignment(ALIGN_BASELINE);
95 }
96 
setFontSize(vcl::Font & rFont)97 void setFontSize(vcl::Font& rFont)
98 {
99     Size aSize(rFont.GetFontSize());
100     aSize.setHeight( (aSize.Height() * 3) / 5 );
101     aSize.setWidth( (aSize.Width() * 3) / 5 );
102     rFont.SetFontSize(aSize);
103 }
104 
calcFontHeightAnyAscent(vcl::RenderContext & rRenderContext,const vcl::Font & rFont,long & nHeight,long & nAscent)105 void calcFontHeightAnyAscent(vcl::RenderContext& rRenderContext, const vcl::Font& rFont, long& nHeight, long& nAscent)
106 {
107     if (!nHeight)
108     {
109         rRenderContext.SetFont(rFont);
110         FontMetric aMetric(rRenderContext.GetFontMetric());
111         nHeight = aMetric.GetLineHeight();
112         nAscent = aMetric.GetAscent();
113     }
114 }
115 
setFont(const SvxFont & rNewFont,SvxFont & rImplFont)116 void setFont(const SvxFont& rNewFont, SvxFont& rImplFont)
117 {
118     rImplFont = rNewFont;
119     rImplFont.SetTransparent(true);
120     rImplFont.SetAlignment(ALIGN_BASELINE);
121 }
122 
123 /*
124  * removes line feeds and carriage returns from string
125  * returns if param is empty
126  */
CleanAndCheckEmpty(OUString & rText)127 bool CleanAndCheckEmpty(OUString& rText)
128 {
129     bool bEmpty = true;
130     for (sal_Int32 i = 0; i < rText.getLength(); ++i)
131     {
132         if (0xa == rText[i] || 0xd == rText[i])
133             rText = rText.replaceAt(i, 1, " ");
134         else
135             bEmpty = false;
136     }
137     return bEmpty;
138 }
139 } // end anonymous namespace
140 
141 class FontPrevWin_Impl
142 {
143     friend class SvxFontPrevWindow;
144 
145     SvxFont maFont;
146     VclPtr<Printer> mpPrinter;
147     bool mbDelPrinter;
148 
149     Reference <XBreakIterator> mxBreak;
150     std::vector<sal_uIntPtr> maTextWidth;
151     std::deque<sal_Int32> maScriptChg;
152     std::vector<sal_uInt16> maScriptType;
153     SvxFont maCJKFont;
154     SvxFont maCTLFont;
155     OUString maText;
156     OUString maScriptText;
157     std::unique_ptr<Color> mpColor;
158     std::unique_ptr<Color> mpBackColor;
159     std::unique_ptr<Color> mpTextLineColor;
160     std::unique_ptr<Color> mpOverlineColor;
161     long mnAscent;
162     sal_Unicode mcStartBracket;
163     sal_Unicode mcEndBracket;
164 
165     long mn100PercentFontWidth; // initial -1 -> not set yet
166     long mn100PercentFontWidthCJK;
167     long mn100PercentFontWidthCTL;
168     sal_uInt16 mnFontWidthScale;
169 
170     bool mbSelection : 1;
171     bool mbGetSelection : 1;
172     bool mbTwoLines : 1;
173     bool mbUseFontNameAsText : 1;
174     bool mbTextInited : 1;
175 
176     bool m_bCJKEnabled;
177     bool m_bCTLEnabled;
178 
179 
180 public:
FontPrevWin_Impl()181     FontPrevWin_Impl() :
182         mpPrinter(nullptr),
183         mbDelPrinter(false),
184         mnAscent(0),
185         mcStartBracket(0),
186         mcEndBracket(0),
187         mnFontWidthScale(100),
188         mbSelection(false),
189         mbGetSelection(false),
190         mbTwoLines(false),
191         mbUseFontNameAsText(false),
192         mbTextInited(false)
193     {
194         SvtLanguageOptions aLanguageOptions;
195         m_bCJKEnabled = aLanguageOptions.IsAnyEnabled();
196         m_bCTLEnabled = aLanguageOptions.IsCTLFontEnabled();
197 
198         Invalidate100PercentFontWidth();
199     }
200 
~FontPrevWin_Impl()201     ~FontPrevWin_Impl()
202     {
203         if (mbDelPrinter)
204             mpPrinter.disposeAndClear();
205     }
206 
207     void CheckScript();
208     Size CalcTextSize(vcl::RenderContext& rRenderContext, OutputDevice const * pPrinter, const SvxFont& rFont);
209     void DrawPrev(vcl::RenderContext& rRenderContext, Printer* pPrinter, Point& rPt, const SvxFont& rFont);
210 
211     bool SetFontWidthScale(sal_uInt16 nScaleInPercent);
212     inline void Invalidate100PercentFontWidth();
213     inline bool Is100PercentFontWidthValid() const;
214     void ScaleFontWidth(vcl::RenderContext const & rRenderContext);
215                             // scales rNonCJKFont and aCJKFont depending on nFontWidthScale and
216                             // sets the 100%-Font-Widths
217 };
218 
Invalidate100PercentFontWidth()219 inline void FontPrevWin_Impl::Invalidate100PercentFontWidth()
220 {
221     mn100PercentFontWidth = mn100PercentFontWidthCJK = mn100PercentFontWidthCTL = -1;
222 }
223 
Is100PercentFontWidthValid() const224 inline bool FontPrevWin_Impl::Is100PercentFontWidthValid() const
225 {
226     DBG_ASSERT( ( mn100PercentFontWidth == -1 && mn100PercentFontWidthCJK == -1 ) ||
227                 ( mn100PercentFontWidth != -1 && mn100PercentFontWidthCJK != -1 ) ||
228                 ( mn100PercentFontWidth == -1 && mn100PercentFontWidthCTL == -1 ) ||
229                 ( mn100PercentFontWidth != -1 && mn100PercentFontWidthCTL != -1 ),
230                 "*FontPrevWin_Impl::Is100PercentFontWidthValid(): 100PercentFontWidth's not synchronous" );
231     return mn100PercentFontWidth != -1;
232 }
233 
234 /*
235  * evaluates the scripttypes of the actual string.
236  * Afterwards the positions of script change are notified in aScriptChg,
237  * the scripttypes in aScriptType.
238  * The aTextWidth array will be filled with zero.
239  */
CheckScript()240 void FontPrevWin_Impl::CheckScript()
241 {
242     assert(!maText.isEmpty()); // must have a preview text here!
243     if (maText == maScriptText)
244     {
245         return; // already initialized
246     }
247 
248     maScriptText = maText;
249 
250     maScriptChg.clear();
251     maScriptType.clear();
252     maTextWidth.clear();
253 
254     if (!mxBreak.is())
255     {
256         Reference<XComponentContext> xContext = ::comphelper::getProcessComponentContext();
257         mxBreak = BreakIterator::create(xContext);
258     }
259 
260     sal_uInt16 nScript = 0;
261     sal_Int32 nChg = 0;
262 
263     while (nChg < maText.getLength())
264     {
265         nScript = mxBreak->getScriptType(maText, nChg);
266         nChg = mxBreak->endOfScript(maText, nChg, nScript);
267         if (nChg < maText.getLength() && nChg > 0 &&
268             (css::i18n::ScriptType::WEAK ==
269              mxBreak->getScriptType(maText, nChg - 1)))
270         {
271             int8_t nType = u_charType(maText[nChg]);
272             if (nType == U_NON_SPACING_MARK || nType == U_ENCLOSING_MARK ||
273                 nType == U_COMBINING_SPACING_MARK)
274             {
275                 maScriptChg.push_back(nChg - 1);
276             }
277             else
278             {
279                 maScriptChg.push_back(nChg);
280             }
281         }
282         else
283         {
284             maScriptChg.push_back(nChg);
285         }
286         maScriptType.push_back(nScript);
287         maTextWidth.push_back(0);
288     }
289 }
290 
291 /*
292  * Size FontPrevWin_Impl::CalcTextSize(..)
293  * fills the aTextWidth array with the text width of every part
294  * of the actual string without a script change inside.
295  * For Latin parts the given rFont will be used,
296  * for Asian parts the aCJKFont.
297  * The returned size contains the whole string.
298  * The member nAscent is calculated to the maximal ascent of all used fonts.
299  */
300 
CalcTextSize(vcl::RenderContext & rRenderContext,OutputDevice const * _pPrinter,const SvxFont & rInFont)301 Size FontPrevWin_Impl::CalcTextSize(vcl::RenderContext& rRenderContext, OutputDevice const * _pPrinter, const SvxFont& rInFont)
302 {
303     sal_uInt16 nScript;
304     sal_uInt16 nIdx = 0;
305     sal_Int32 nStart = 0;
306     sal_Int32 nEnd;
307     size_t nCnt = maScriptChg.size();
308 
309     if (nCnt)
310     {
311         nEnd = maScriptChg[nIdx];
312         nScript = maScriptType[nIdx];
313     }
314     else
315     {
316         nEnd = maText.getLength();
317         nScript = css::i18n::ScriptType::LATIN;
318     }
319     long nTxtWidth = 0;
320     long nCJKHeight = 0;
321     long nCTLHeight = 0;
322     long nHeight = 0;
323     mnAscent = 0;
324     long nCJKAscent = 0;
325     long nCTLAscent = 0;
326 
327     do
328     {
329         const SvxFont& rFont = (nScript == css::i18n::ScriptType::ASIAN) ?
330                                     maCJKFont :
331                                     ((nScript == css::i18n::ScriptType::COMPLEX) ?
332                                         maCTLFont :
333                                         rInFont);
334         sal_uIntPtr nWidth = rFont.GetTextSize(_pPrinter, maText, nStart, nEnd - nStart).Width();
335         if (nIdx >= maTextWidth.size())
336             break;
337 
338         maTextWidth[nIdx++] = nWidth;
339         nTxtWidth += nWidth;
340 
341         switch (nScript)
342         {
343             case css::i18n::ScriptType::ASIAN:
344                 calcFontHeightAnyAscent(rRenderContext, maCJKFont, nCJKHeight, nCJKAscent);
345                 break;
346             case css::i18n::ScriptType::COMPLEX:
347                 calcFontHeightAnyAscent(rRenderContext, maCTLFont, nCTLHeight, nCTLAscent);
348                 break;
349             default:
350                 calcFontHeightAnyAscent(rRenderContext, rFont, nHeight, mnAscent);
351         }
352 
353         if (nEnd < maText.getLength() && nIdx < nCnt)
354         {
355             nStart = nEnd;
356             nEnd = maScriptChg[nIdx];
357             nScript = maScriptType[nIdx];
358         }
359         else
360             break;
361     }
362     while(true);
363 
364     nHeight -= mnAscent;
365     nCJKHeight -= nCJKAscent;
366     nCTLHeight -= nCTLAscent;
367 
368     if (nHeight < nCJKHeight)
369         nHeight = nCJKHeight;
370 
371     if (mnAscent < nCJKAscent)
372         mnAscent = nCJKAscent;
373 
374     if (nHeight < nCTLHeight)
375         nHeight = nCTLHeight;
376 
377     if (mnAscent < nCTLAscent)
378         mnAscent = nCTLAscent;
379 
380     nHeight += mnAscent;
381 
382     Size aTxtSize(nTxtWidth, nHeight);
383     return aTxtSize;
384 }
385 
386 /*
387  * void FontPrevWin_Impl::DrawPrev(..)
388  * calls SvxFont::DrawPrev(..) for every part of the string without a script
389  * change inside, for Asian parts the aCJKFont will be used, otherwise the
390  * given rFont.
391  */
392 
DrawPrev(vcl::RenderContext & rRenderContext,Printer * _pPrinter,Point & rPt,const SvxFont & rInFont)393 void FontPrevWin_Impl::DrawPrev(vcl::RenderContext& rRenderContext, Printer* _pPrinter, Point &rPt, const SvxFont& rInFont)
394 {
395     vcl::Font aOldFont = _pPrinter->GetFont();
396     sal_uInt16 nScript;
397     sal_uInt16 nIdx = 0;
398     sal_Int32 nStart = 0;
399     sal_Int32 nEnd;
400     size_t nCnt = maScriptChg.size();
401     if (nCnt)
402     {
403         nEnd = maScriptChg[nIdx];
404         nScript = maScriptType[nIdx];
405     }
406     else
407     {
408         nEnd = maText.getLength();
409         nScript = css::i18n::ScriptType::LATIN;
410     }
411     do
412     {
413         const SvxFont& rFont = (nScript == css::i18n::ScriptType::ASIAN)
414                                     ? maCJKFont
415                                     : ((nScript == css::i18n::ScriptType::COMPLEX)
416                                         ? maCTLFont
417                                         : rInFont);
418         _pPrinter->SetFont(rFont);
419 
420         rFont.DrawPrev(&rRenderContext, _pPrinter, rPt, maText, nStart, nEnd - nStart);
421 
422         rPt.AdjustX(maTextWidth[nIdx++] );
423         if (nEnd < maText.getLength() && nIdx < nCnt)
424         {
425             nStart = nEnd;
426             nEnd = maScriptChg[nIdx];
427             nScript = maScriptType[nIdx];
428         }
429         else
430             break;
431     }
432     while(true);
433     _pPrinter->SetFont(aOldFont);
434 }
435 
436 
SetFontWidthScale(sal_uInt16 nScale)437 bool FontPrevWin_Impl::SetFontWidthScale(sal_uInt16 nScale)
438 {
439     if (mnFontWidthScale != nScale)
440     {
441         mnFontWidthScale = nScale;
442         return true;
443     }
444 
445     return false;
446 }
447 
ScaleFontWidth(vcl::RenderContext const & rOutDev)448 void FontPrevWin_Impl::ScaleFontWidth(vcl::RenderContext const & rOutDev)
449 {
450     if (!Is100PercentFontWidthValid())
451     {
452         scaleFontWidth(maFont, rOutDev, mn100PercentFontWidth);
453         scaleFontWidth(maCJKFont, rOutDev, mn100PercentFontWidthCJK);
454         scaleFontWidth(maCTLFont, rOutDev, mn100PercentFontWidthCTL);
455     }
456 
457     maFont.SetAverageFontWidth(mn100PercentFontWidth * mnFontWidthScale / 100);
458     maCJKFont.SetAverageFontWidth(mn100PercentFontWidthCJK * mnFontWidthScale / 100);
459     maCTLFont.SetAverageFontWidth(mn100PercentFontWidthCTL * mnFontWidthScale / 100);
460 }
461 
GetWhich(const SfxItemSet & rSet,sal_uInt16 nSlot,sal_uInt16 & rWhich)462 static bool GetWhich (const SfxItemSet& rSet, sal_uInt16 nSlot, sal_uInt16& rWhich)
463 {
464     rWhich = rSet.GetPool()->GetWhich(nSlot);
465     return rSet.GetItemState(rWhich) >= SfxItemState::DEFAULT;
466 }
467 
SetPrevFont(const SfxItemSet & rSet,sal_uInt16 nSlot,SvxFont & rFont)468 static void SetPrevFont(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
469 {
470     sal_uInt16 nWhich;
471     if (GetWhich(rSet, nSlot, nWhich))
472     {
473         const SvxFontItem& rFontItem = static_cast<const SvxFontItem&>(rSet.Get(nWhich));
474         rFont.SetFamily(rFontItem.GetFamily());
475         rFont.SetFamilyName(rFontItem.GetFamilyName());
476         rFont.SetPitch(rFontItem.GetPitch());
477         rFont.SetCharSet(rFontItem.GetCharSet());
478         rFont.SetStyleName(rFontItem.GetStyleName());
479     }
480 }
481 
SetPrevFontStyle(const SfxItemSet & rSet,sal_uInt16 nPosture,sal_uInt16 nWeight,SvxFont & rFont)482 static void SetPrevFontStyle( const SfxItemSet& rSet, sal_uInt16 nPosture, sal_uInt16 nWeight, SvxFont& rFont )
483 {
484     sal_uInt16 nWhich;
485     if( GetWhich( rSet, nPosture, nWhich ) )
486     {
487         const SvxPostureItem& rItem = static_cast<const SvxPostureItem&>( rSet.Get( nWhich ) );
488         rFont.SetItalic( rItem.GetValue() != ITALIC_NONE ? ITALIC_NORMAL : ITALIC_NONE );
489     }
490 
491     if( GetWhich( rSet, nWeight, nWhich ) )
492     {
493         const SvxWeightItem& rItem = static_cast<const SvxWeightItem&>( rSet.Get( nWhich ) );
494         rFont.SetWeight( rItem.GetValue() != WEIGHT_NORMAL ? WEIGHT_BOLD : WEIGHT_NORMAL );
495     }
496 }
497 
SetPrevFontEscapement(SvxFont & rFont,sal_uInt8 nProp,sal_uInt8 nEscProp,short nEsc)498 static void SetPrevFontEscapement(SvxFont& rFont, sal_uInt8 nProp, sal_uInt8 nEscProp, short nEsc)
499 {
500     rFont.SetPropr(nProp);
501     rFont.SetProprRel(nEscProp);
502     rFont.SetEscapement(nEsc);
503 }
504 
ApplySettings(vcl::RenderContext & rRenderContext)505 void SvxFontPrevWindow::ApplySettings(vcl::RenderContext& rRenderContext)
506 {
507     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
508 
509     svtools::ColorConfig aColorConfig;
510     Color aTextColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor);
511     rRenderContext.SetTextColor(aTextColor);
512 
513     rRenderContext.SetBackground(rStyleSettings.GetWindowColor());
514 }
515 
SetDrawingArea(weld::DrawingArea * pDrawingArea)516 void SvxFontPrevWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
517 {
518     CustomWidgetController::SetDrawingArea(pDrawingArea);
519     Size aPrefSize(getPreviewStripSize(pDrawingArea->get_ref_device()));
520     pDrawingArea->set_size_request(aPrefSize.Width(), aPrefSize.Height());
521 
522     pImpl.reset(new FontPrevWin_Impl);
523     SfxViewShell* pSh = SfxViewShell::Current();
524 
525     if (pSh)
526         pImpl->mpPrinter = pSh->GetPrinter();
527 
528     if (!pImpl->mpPrinter)
529     {
530         pImpl->mpPrinter = VclPtr<Printer>::Create();
531         pImpl->mbDelPrinter = true;
532     }
533     initFont(pImpl->maFont);
534     initFont(pImpl->maCJKFont);
535     initFont(pImpl->maCTLFont);
536 
537     Invalidate();
538 }
539 
SvxFontPrevWindow()540 SvxFontPrevWindow::SvxFontPrevWindow()
541 {
542 }
543 
~SvxFontPrevWindow()544 SvxFontPrevWindow::~SvxFontPrevWindow()
545 {
546 }
547 
GetCTLFont()548 SvxFont& SvxFontPrevWindow::GetCTLFont()
549 {
550     return pImpl->maCTLFont;
551 }
552 
GetCJKFont()553 SvxFont& SvxFontPrevWindow::GetCJKFont()
554 {
555     return pImpl->maCJKFont;
556 }
557 
GetFont()558 SvxFont& SvxFontPrevWindow::GetFont()
559 {
560     pImpl->Invalidate100PercentFontWidth();     // because the user might change the size
561     return pImpl->maFont;
562 }
563 
GetFont() const564 const SvxFont& SvxFontPrevWindow::GetFont() const
565 {
566     return pImpl->maFont;
567 }
568 
SetPreviewText(const OUString & rString)569 void SvxFontPrevWindow::SetPreviewText( const OUString& rString )
570 {
571     pImpl->maText = rString;
572     pImpl->mbTextInited = true;
573 }
574 
SetFontNameAsPreviewText()575 void SvxFontPrevWindow::SetFontNameAsPreviewText()
576 {
577     pImpl->mbUseFontNameAsText = true;
578 }
579 
SetFont(const SvxFont & rNormalOutFont,const SvxFont & rCJKOutFont,const SvxFont & rCTLFont)580 void SvxFontPrevWindow::SetFont( const SvxFont& rNormalOutFont, const SvxFont& rCJKOutFont, const SvxFont& rCTLFont )
581 {
582     setFont(rNormalOutFont, pImpl->maFont);
583     setFont(rCJKOutFont, pImpl->maCJKFont);
584     setFont(rCTLFont, pImpl->maCTLFont);
585 
586     pImpl->Invalidate100PercentFontWidth();
587     Invalidate();
588 }
589 
SetColor(const Color & rColor)590 void SvxFontPrevWindow::SetColor(const Color &rColor)
591 {
592     pImpl->mpColor.reset(new Color(rColor));
593     Invalidate();
594 }
595 
ResetColor()596 void SvxFontPrevWindow::ResetColor()
597 {
598     pImpl->mpColor.reset();
599     Invalidate();
600 }
601 
SetBackColor(const Color & rColor)602 void SvxFontPrevWindow::SetBackColor(const Color &rColor)
603 {
604     pImpl->mpBackColor.reset(new Color(rColor));
605     Invalidate();
606 }
607 
SetTextLineColor(const Color & rColor)608 void SvxFontPrevWindow::SetTextLineColor(const Color &rColor)
609 {
610     pImpl->mpTextLineColor.reset(new Color(rColor));
611     Invalidate();
612 }
613 
SetOverlineColor(const Color & rColor)614 void SvxFontPrevWindow::SetOverlineColor(const Color &rColor)
615 {
616     pImpl->mpOverlineColor.reset(new Color(rColor));
617     Invalidate();
618 }
619 
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle &)620 void SvxFontPrevWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
621 {
622     rRenderContext.Push(PushFlags::ALL);
623     rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
624 
625     ApplySettings(rRenderContext);
626 
627     Printer* pPrinter = pImpl->mpPrinter;
628     const SvxFont& rFont = pImpl->maFont;
629     const SvxFont& rCJKFont = pImpl->maCJKFont;
630     const SvxFont& rCTLFont = pImpl->maCTLFont;
631 
632     if (!IsEnabled())
633     {
634         const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
635         const Size aLogSize(rRenderContext.GetOutputSize());
636 
637         tools::Rectangle aRect(Point(0, 0), aLogSize);
638         rRenderContext.SetLineColor();
639         rRenderContext.SetFillColor(rStyleSettings.GetWindowColor());
640         rRenderContext.DrawRect(aRect);
641     }
642     else
643     {
644         if (!pImpl->mbSelection && !pImpl->mbTextInited)
645         {
646             using namespace css::i18n::ScriptType;
647 
648             SfxViewShell* pSh = SfxViewShell::Current();
649 
650             if (pSh && !pImpl->mbGetSelection && !pImpl->mbUseFontNameAsText)
651             {
652                 pImpl->maText = pSh->GetSelectionText();
653                 pImpl->mbGetSelection = true;
654                 pImpl->mbSelection = !CleanAndCheckEmpty(pImpl->maText);
655             }
656 
657             if (!pImpl->mbSelection || pImpl->mbUseFontNameAsText)
658             {
659                 //If we're showing multiple sample texts, then they're all
660                 //sample texts. If only showing Latin, continue to use
661                 //the fontname as the preview
662                 if ((pImpl->m_bCJKEnabled) || (pImpl->m_bCTLEnabled))
663                     pImpl->maText = makeRepresentativeTextForFont(LATIN, rFont);
664                 else
665                     pImpl->maText = rFont.GetFamilyName();
666 
667                 if (pImpl->m_bCJKEnabled)
668                 {
669                     if (!pImpl->maText.isEmpty())
670                         pImpl->maText += "   ";
671                     pImpl->maText += makeRepresentativeTextForFont(ASIAN, rCJKFont);
672 
673                 }
674                 if (pImpl->m_bCTLEnabled)
675                 {
676                     if (!pImpl->maText.isEmpty())
677                         pImpl->maText += "   ";
678                     pImpl->maText += makeRepresentativeTextForFont(COMPLEX, rCTLFont);
679                 }
680             }
681 
682             if (pImpl->maText.isEmpty())
683             {   // fdo#58427: still no text? let's try that one...
684                 pImpl->maText = makeRepresentativeTextForFont(LATIN, rFont);
685             }
686 
687             bool bEmpty = CleanAndCheckEmpty(pImpl->maText);
688             if (bEmpty)
689                 pImpl->maText = OUString();
690 
691             if (pImpl->maText.getLength() > (TEXT_WIDTH - 1))
692             {
693                 const sal_Int32 nSpaceIdx = pImpl->maText.indexOf(" ", TEXT_WIDTH);
694                 if (nSpaceIdx != -1)
695                     pImpl->maText = pImpl->maText.copy(0, nSpaceIdx);
696                 else
697                     pImpl->maText = pImpl->maText.copy(0, (TEXT_WIDTH - 1));
698             }
699         }
700 
701         // calculate text width scaling
702         pImpl->ScaleFontWidth(rRenderContext);
703 
704         pImpl->CheckScript();
705         Size aTxtSize = pImpl->CalcTextSize(rRenderContext, pPrinter, rFont);
706 
707         const Size aLogSize(rRenderContext.GetOutputSize());
708 
709         long nX = aLogSize.Width()  / 2 - aTxtSize.Width() / 2;
710         long nY = aLogSize.Height() / 2 - aTxtSize.Height() / 2;
711 
712         if (nY + pImpl->mnAscent > aLogSize.Height())
713             nY = aLogSize.Height() - pImpl->mnAscent;
714 
715         if (pImpl->mpBackColor)
716         {
717             tools::Rectangle aRect(Point(0, 0), aLogSize);
718             Color aLineCol = rRenderContext.GetLineColor();
719             Color aFillCol = rRenderContext.GetFillColor();
720             rRenderContext.SetLineColor();
721             rRenderContext.SetFillColor(*pImpl->mpBackColor);
722             rRenderContext.DrawRect(aRect);
723             rRenderContext.SetLineColor(aLineCol);
724             rRenderContext.SetFillColor(aFillCol);
725         }
726         if (pImpl->mpColor)
727         {
728             tools::Rectangle aRect(Point(nX, nY), aTxtSize);
729             Color aLineCol = rRenderContext.GetLineColor();
730             Color aFillCol = rRenderContext.GetFillColor();
731             rRenderContext.SetLineColor();
732             rRenderContext.SetFillColor(*pImpl->mpColor);
733             rRenderContext.DrawRect(aRect);
734             rRenderContext.SetLineColor(aLineCol);
735             rRenderContext.SetFillColor(aFillCol);
736         }
737 
738         if (pImpl->mpTextLineColor)
739         {
740             rRenderContext.SetTextLineColor(*pImpl->mpTextLineColor);
741         }
742 
743         if (pImpl->mpOverlineColor)
744         {
745             rRenderContext.SetOverlineColor(*pImpl->mpOverlineColor);
746         }
747 
748         long nStdAscent = pImpl->mnAscent;
749         nY += nStdAscent;
750 
751         if (IsTwoLines())
752         {
753             SvxFont aSmallFont(rFont);
754             Size aOldSize = pImpl->maCJKFont.GetFontSize();
755             setFontSize(aSmallFont);
756             setFontSize(pImpl->maCJKFont);
757 
758             long nStartBracketWidth = 0;
759             long nEndBracketWidth = 0;
760             long nTextWidth = 0;
761             if (pImpl->mcStartBracket)
762             {
763                 OUString sBracket(pImpl->mcStartBracket);
764                 nStartBracketWidth = rFont.GetTextSize(pPrinter, sBracket).Width();
765             }
766             if (pImpl->mcEndBracket)
767             {
768                 OUString sBracket(pImpl->mcEndBracket);
769                 nEndBracketWidth = rFont.GetTextSize(pPrinter, sBracket).Width();
770             }
771             nTextWidth = pImpl->CalcTextSize(rRenderContext, pPrinter, aSmallFont).Width();
772             long nResultWidth = nStartBracketWidth;
773             nResultWidth += nEndBracketWidth;
774             nResultWidth += nTextWidth;
775 
776             long _nX = (aLogSize.Width() - nResultWidth) / 2;
777             rRenderContext.DrawLine(Point(0,  nY), Point(_nX, nY));
778             rRenderContext.DrawLine(Point(_nX + nResultWidth, nY), Point(aLogSize.Width(), nY));
779 
780             long nSmallAscent = pImpl->mnAscent;
781             long nOffset = (nStdAscent - nSmallAscent) / 2;
782 
783             if (pImpl->mcStartBracket)
784             {
785                 OUString sBracket(pImpl->mcStartBracket);
786                 rFont.DrawPrev(&rRenderContext, pPrinter, Point(_nX, nY - nOffset - 4), sBracket);
787                 _nX += nStartBracketWidth;
788             }
789 
790             Point aTmpPoint1(_nX, nY - nSmallAscent - 2);
791             Point aTmpPoint2(_nX, nY);
792             pImpl->DrawPrev(rRenderContext, pPrinter, aTmpPoint1, aSmallFont);
793             pImpl->DrawPrev(rRenderContext, pPrinter, aTmpPoint2, aSmallFont);
794 
795             _nX += nTextWidth;
796             if (pImpl->mcEndBracket)
797             {
798                 Point aTmpPoint( _nX + 1, nY - nOffset - 4);
799                 OUString sBracket(pImpl->mcEndBracket);
800                 rFont.DrawPrev(&rRenderContext, pPrinter, aTmpPoint, sBracket);
801             }
802             pImpl->maCJKFont.SetFontSize(aOldSize);
803         }
804         else
805         {
806 
807             Color aLineCol = rRenderContext.GetLineColor();
808 
809             rRenderContext.SetLineColor(rFont.GetColor());
810             rRenderContext.DrawLine(Point(0,  nY), Point(nX, nY));
811             rRenderContext.DrawLine(Point(nX + aTxtSize.Width(), nY), Point(aLogSize.Width(), nY));
812             rRenderContext.SetLineColor(aLineCol);
813 
814             Point aTmpPoint(nX, nY);
815             pImpl->DrawPrev(rRenderContext, pPrinter, aTmpPoint, rFont);
816         }
817     }
818     rRenderContext.Pop();
819 }
820 
IsTwoLines() const821 bool SvxFontPrevWindow::IsTwoLines() const
822 {
823     return pImpl->mbTwoLines;
824 }
825 
SetTwoLines(bool bSet)826 void SvxFontPrevWindow::SetTwoLines(bool bSet)
827 {
828     pImpl->mbTwoLines = bSet;
829 }
830 
SetBrackets(sal_Unicode cStart,sal_Unicode cEnd)831 void SvxFontPrevWindow::SetBrackets(sal_Unicode cStart, sal_Unicode cEnd)
832 {
833     pImpl->mcStartBracket = cStart;
834     pImpl->mcEndBracket = cEnd;
835 }
836 
SetFontWidthScale(sal_uInt16 n)837 void SvxFontPrevWindow::SetFontWidthScale( sal_uInt16 n )
838 {
839     if (pImpl->SetFontWidthScale(n))
840         Invalidate();
841 }
842 
AutoCorrectFontColor()843 void SvxFontPrevWindow::AutoCorrectFontColor()
844 {
845     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
846     Color aFontColor(rStyleSettings.GetWindowTextColor());
847 
848     if (COL_AUTO == pImpl->maFont.GetColor())
849         pImpl->maFont.SetColor(aFontColor);
850 
851     if (COL_AUTO == pImpl->maCJKFont.GetColor())
852         pImpl->maCJKFont.SetColor(aFontColor);
853 
854     if (COL_AUTO == pImpl->maCTLFont.GetColor())
855         pImpl->maCTLFont.SetColor(aFontColor);
856 }
857 
SetFontSize(const SfxItemSet & rSet,sal_uInt16 nSlot,SvxFont & rFont)858 void SvxFontPrevWindow::SetFontSize( const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont )
859 {
860     sal_uInt16 nWhich;
861     long nH;
862     if (GetWhich(rSet, nSlot, nWhich))
863     {
864         nH = OutputDevice::LogicToLogic(static_cast<const SvxFontHeightItem&>(rSet.Get(nWhich)).GetHeight(),
865                           rSet.GetPool()->GetMetric(nWhich),
866                           MapUnit::MapTwip);
867     }
868     else
869         nH = 240;// as default 12pt
870 
871     rFont.SetFontSize(Size(0, nH));
872 }
873 
SetFontLang(const SfxItemSet & rSet,sal_uInt16 nSlot,SvxFont & rFont)874 void SvxFontPrevWindow::SetFontLang(const SfxItemSet& rSet, sal_uInt16 nSlot, SvxFont& rFont)
875 {
876     sal_uInt16 nWhich;
877     LanguageType nLang;
878     if( GetWhich( rSet, nSlot, nWhich ) )
879         nLang = static_cast<const SvxLanguageItem&>(rSet.Get(nWhich)).GetLanguage();
880     else
881         nLang = LANGUAGE_NONE;
882     rFont.SetLanguage(nLang);
883 }
884 
SetFromItemSet(const SfxItemSet & rSet,bool bPreviewBackgroundToCharacter)885 void SvxFontPrevWindow::SetFromItemSet(const SfxItemSet &rSet, bool bPreviewBackgroundToCharacter)
886 {
887     sal_uInt16 nWhich;
888     SvxFont& rFont = GetFont();
889     SvxFont& rCJKFont = GetCJKFont();
890     SvxFont& rCTLFont = GetCTLFont();
891 
892     // Preview string
893     if( GetWhich( rSet, SID_CHAR_DLG_PREVIEW_STRING, nWhich ) )
894     {
895         const SfxStringItem& rItem = static_cast<const SfxStringItem&>( rSet.Get( nWhich ) );
896         const OUString& aString = rItem.GetValue();
897         if( !aString.isEmpty() )
898             SetPreviewText( aString );
899         else
900             SetFontNameAsPreviewText();
901     }
902 
903     // Underline
904     FontLineStyle eUnderline;
905     if( GetWhich( rSet, SID_ATTR_CHAR_UNDERLINE, nWhich ) )
906     {
907         const SvxUnderlineItem& rItem = static_cast<const SvxUnderlineItem&>( rSet.Get( nWhich ) );
908         eUnderline = rItem.GetValue();
909     }
910     else
911         eUnderline = LINESTYLE_NONE;
912 
913     rFont.SetUnderline( eUnderline );
914     rCJKFont.SetUnderline( eUnderline );
915     rCTLFont.SetUnderline( eUnderline );
916 
917     // Overline
918     FontLineStyle eOverline;
919     if( GetWhich( rSet, SID_ATTR_CHAR_OVERLINE, nWhich ) )
920     {
921         const SvxOverlineItem& rItem = static_cast<const SvxOverlineItem&>( rSet.Get( nWhich ) );
922         eOverline = rItem.GetValue();
923     }
924     else
925         eOverline = LINESTYLE_NONE;
926 
927     rFont.SetOverline( eOverline );
928     rCJKFont.SetOverline( eOverline );
929     rCTLFont.SetOverline( eOverline );
930 
931     //  Strikeout
932     FontStrikeout eStrikeout;
933     if( GetWhich( rSet, SID_ATTR_CHAR_STRIKEOUT, nWhich ) )
934     {
935         const SvxCrossedOutItem& rItem = static_cast<const SvxCrossedOutItem&>( rSet.Get( nWhich ) );
936         eStrikeout = rItem.GetValue();
937     }
938     else
939         eStrikeout = STRIKEOUT_NONE;
940 
941     rFont.SetStrikeout( eStrikeout );
942     rCJKFont.SetStrikeout( eStrikeout );
943     rCTLFont.SetStrikeout( eStrikeout );
944 
945     // WordLineMode
946     if( GetWhich( rSet, SID_ATTR_CHAR_WORDLINEMODE, nWhich ) )
947     {
948         const SvxWordLineModeItem& rItem = static_cast<const SvxWordLineModeItem&>( rSet.Get( nWhich ) );
949         rFont.SetWordLineMode( rItem.GetValue() );
950         rCJKFont.SetWordLineMode( rItem.GetValue() );
951         rCTLFont.SetWordLineMode( rItem.GetValue() );
952     }
953 
954     // Emphasis
955     if( GetWhich( rSet, SID_ATTR_CHAR_EMPHASISMARK, nWhich ) )
956     {
957         const SvxEmphasisMarkItem& rItem = static_cast<const SvxEmphasisMarkItem&>( rSet.Get( nWhich ) );
958         FontEmphasisMark eMark = rItem.GetEmphasisMark();
959         rFont.SetEmphasisMark( eMark );
960         rCJKFont.SetEmphasisMark( eMark );
961         rCTLFont.SetEmphasisMark( eMark );
962     }
963 
964     // Relief
965     if( GetWhich( rSet, SID_ATTR_CHAR_RELIEF, nWhich ) )
966     {
967         const SvxCharReliefItem& rItem = static_cast<const SvxCharReliefItem&>( rSet.Get( nWhich ) );
968         FontRelief eFontRelief = rItem.GetValue();
969         rFont.SetRelief( eFontRelief );
970         rCJKFont.SetRelief( eFontRelief );
971         rCTLFont.SetRelief( eFontRelief );
972     }
973 
974     // Effects
975     if( GetWhich( rSet, SID_ATTR_CHAR_CASEMAP, nWhich ) )
976     {
977         const SvxCaseMapItem& rItem = static_cast<const SvxCaseMapItem&>( rSet.Get( nWhich ) );
978         SvxCaseMap eCaseMap = rItem.GetValue();
979         rFont.SetCaseMap( eCaseMap );
980         rCJKFont.SetCaseMap( eCaseMap );
981         // #i78474# small caps do not exist in CTL fonts
982         rCTLFont.SetCaseMap( eCaseMap == SvxCaseMap::SmallCaps ? SvxCaseMap::NotMapped : eCaseMap );
983     }
984 
985     // Outline
986     if( GetWhich( rSet, SID_ATTR_CHAR_CONTOUR, nWhich ) )
987     {
988         const SvxContourItem& rItem = static_cast<const  SvxContourItem&>( rSet.Get( nWhich ) );
989         bool bOutline = rItem.GetValue();
990         rFont.SetOutline( bOutline );
991         rCJKFont.SetOutline( bOutline );
992         rCTLFont.SetOutline( bOutline );
993     }
994 
995     // Shadow
996     if( GetWhich( rSet, SID_ATTR_CHAR_SHADOWED, nWhich ) )
997     {
998         const SvxShadowedItem& rItem = static_cast<const  SvxShadowedItem&>( rSet.Get( nWhich ) );
999         bool bShadow = rItem.GetValue();
1000         rFont.SetShadow( bShadow );
1001         rCJKFont.SetShadow( bShadow );
1002         rCTLFont.SetShadow( bShadow );
1003     }
1004 
1005     // Background
1006     bool bTransparent;
1007     if( GetWhich( rSet, bPreviewBackgroundToCharacter ? SID_ATTR_BRUSH : SID_ATTR_BRUSH_CHAR, nWhich ) )
1008     {
1009          const SvxBrushItem& rBrush = static_cast<const SvxBrushItem&>( rSet.Get( nWhich ) );
1010          const Color& rColor = rBrush.GetColor();
1011          bTransparent = rColor.GetTransparency() > 0;
1012          rFont.SetFillColor( rColor );
1013          rCJKFont.SetFillColor( rColor );
1014          rCTLFont.SetFillColor( rColor );
1015     }
1016     else
1017         bTransparent = true;
1018 
1019     rFont.SetTransparent( bTransparent );
1020     rCJKFont.SetTransparent( bTransparent );
1021     rCTLFont.SetTransparent( bTransparent );
1022 
1023     Color aBackCol( COL_TRANSPARENT );
1024     if( !bPreviewBackgroundToCharacter )
1025     {
1026         if( GetWhich( rSet, SID_ATTR_BRUSH, nWhich ) )
1027         {
1028             const SvxBrushItem& rBrush = static_cast<const  SvxBrushItem&>( rSet.Get( nWhich ) );
1029             if( GPOS_NONE == rBrush.GetGraphicPos() )
1030                 aBackCol = rBrush.GetColor();
1031         }
1032     }
1033     SetBackColor( aBackCol );
1034 
1035     // Font
1036     SetPrevFont( rSet, SID_ATTR_CHAR_FONT, rFont );
1037     SetPrevFont( rSet, SID_ATTR_CHAR_CJK_FONT, rCJKFont );
1038     SetPrevFont( rSet, SID_ATTR_CHAR_CTL_FONT, rCTLFont );
1039 
1040     // Style
1041     SetPrevFontStyle( rSet, SID_ATTR_CHAR_POSTURE, SID_ATTR_CHAR_WEIGHT, rFont );
1042     SetPrevFontStyle( rSet, SID_ATTR_CHAR_CJK_POSTURE, SID_ATTR_CHAR_CJK_WEIGHT, rCJKFont );
1043     SetPrevFontStyle( rSet, SID_ATTR_CHAR_CTL_POSTURE, SID_ATTR_CHAR_CTL_WEIGHT, rCTLFont );
1044 
1045     // Size
1046     SetFontSize( rSet, SID_ATTR_CHAR_FONTHEIGHT, rFont );
1047     SetFontSize( rSet, SID_ATTR_CHAR_CJK_FONTHEIGHT, rCJKFont );
1048     SetFontSize( rSet, SID_ATTR_CHAR_CTL_FONTHEIGHT, rCTLFont );
1049 
1050     // Language
1051     SetFontLang( rSet, SID_ATTR_CHAR_LANGUAGE, rFont );
1052     SetFontLang( rSet, SID_ATTR_CHAR_CJK_LANGUAGE, rCJKFont );
1053     SetFontLang( rSet, SID_ATTR_CHAR_CTL_LANGUAGE, rCTLFont );
1054 
1055     // Color
1056     if( GetWhich( rSet, SID_ATTR_CHAR_COLOR, nWhich ) )
1057     {
1058         const SvxColorItem& rItem = static_cast<const SvxColorItem&>( rSet.Get( nWhich ) );
1059         Color aCol( rItem.GetValue() );
1060         rFont.SetColor( aCol );
1061 
1062         rCJKFont.SetColor( aCol );
1063         rCTLFont.SetColor( aCol );
1064 
1065         AutoCorrectFontColor(); // handle color COL_AUTO
1066     }
1067 
1068     // Kerning
1069     if( GetWhich( rSet, SID_ATTR_CHAR_KERNING, nWhich ) )
1070     {
1071         const SvxKerningItem& rItem = static_cast<const SvxKerningItem&>( rSet.Get( nWhich ) );
1072         short nKern = static_cast<short>(OutputDevice::LogicToLogic(rItem.GetValue(), rSet.GetPool()->GetMetric(nWhich), MapUnit::MapTwip));
1073         rFont.SetFixKerning( nKern );
1074         rCJKFont.SetFixKerning( nKern );
1075         rCTLFont.SetFixKerning( nKern );
1076     }
1077 
1078     // Escapement
1079     const sal_uInt8 nProp = 100;
1080     short nEsc;
1081     sal_uInt8 nEscProp;
1082     if( GetWhich( rSet, SID_ATTR_CHAR_ESCAPEMENT, nWhich ) )
1083     {
1084         const SvxEscapementItem& rItem = static_cast<const SvxEscapementItem&>( rSet.Get( nWhich ) );
1085         nEsc = rItem.GetEsc();
1086         nEscProp = rItem.GetProportionalHeight();
1087 
1088         if( nEsc == DFLT_ESC_AUTO_SUPER )
1089             nEsc = DFLT_ESC_SUPER;
1090         else if( nEsc == DFLT_ESC_AUTO_SUB )
1091             nEsc = DFLT_ESC_SUB;
1092     }
1093     else
1094     {
1095         nEsc  = 0;
1096         nEscProp = 100;
1097     }
1098     SetPrevFontEscapement( rFont, nProp, nEscProp, nEsc );
1099     SetPrevFontEscapement( rCJKFont, nProp, nEscProp, nEsc );
1100     SetPrevFontEscapement( rCTLFont, nProp, nEscProp, nEsc );
1101 
1102     // Font width scale
1103     if( GetWhich( rSet, SID_ATTR_CHAR_SCALEWIDTH, nWhich ) )
1104     {
1105         const SvxCharScaleWidthItem&rItem = static_cast<const SvxCharScaleWidthItem&>( rSet.Get( nWhich ) );
1106         SetFontWidthScale( rItem.GetValue() );
1107     }
1108 
1109     Invalidate();
1110 }
1111 
1112 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1113