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