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