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 "PresenterTheme.hxx"
21 #include "PresenterBitmapContainer.hxx"
22 #include "PresenterCanvasHelper.hxx"
23 #include "PresenterConfigurationAccess.hxx"
24 #include <com/sun/star/drawing/XPresenterHelper.hpp>
25 #include <com/sun/star/rendering/PanoseWeight.hpp>
26 #include <osl/diagnose.h>
27 #include <map>
28 #include <numeric>
29 
30 using namespace ::com::sun::star;
31 using namespace ::com::sun::star::uno;
32 using namespace ::std;
33 
34 namespace sdext::presenter {
35 
36 namespace {
37 
38 class BorderSize
39 {
40 public:
41     const static sal_Int32 mnInvalidValue = -10000;
42 
BorderSize()43     BorderSize() : mnLeft(mnInvalidValue),
44                         mnTop(mnInvalidValue),
45                         mnRight(mnInvalidValue),
46                         mnBottom(mnInvalidValue) {}
47 
48     sal_Int32 mnLeft;
49     sal_Int32 mnTop;
50     sal_Int32 mnRight;
51     sal_Int32 mnBottom;
52 
ToVector()53     vector<sal_Int32> ToVector()
54     {
55         return
56         {
57             mnLeft == mnInvalidValue ? 0 : mnLeft,
58             mnTop == mnInvalidValue ? 0 : mnTop,
59             mnRight == mnInvalidValue ? 0 : mnRight,
60             mnBottom == mnInvalidValue ? 0 : mnBottom
61         };
62     };
63 
Merge(const BorderSize & rBorderSize)64     void Merge (const BorderSize& rBorderSize)
65     {
66         if (mnLeft == mnInvalidValue)
67             mnLeft = rBorderSize.mnLeft;
68         if (mnTop == mnInvalidValue)
69             mnTop = rBorderSize.mnTop;
70         if (mnRight == mnInvalidValue)
71             mnRight = rBorderSize.mnRight;
72         if (mnBottom == mnInvalidValue)
73             mnBottom = rBorderSize.mnBottom;
74     }
75 };
76 
77 /** Reading a theme from the configurations is done in various classes.  The
78     ReadContext gives access to frequently used objects and functions to make
79     the configuration handling easier.
80 */
81 class ReadContext
82 {
83 public:
84     Reference<XComponentContext> mxComponentContext;
85     Reference<rendering::XCanvas> mxCanvas;
86     Reference<drawing::XPresenterHelper> mxPresenterHelper;
87 
88     ReadContext (
89         const Reference<XComponentContext>& rxContext,
90         const Reference<rendering::XCanvas>& rxCanvas);
91 
92     /** Read data describing a font from the node that can be reached from
93         the given root via the given path.
94         @param rsFontPath
95             May be empty.
96     */
97     static PresenterTheme::SharedFontDescriptor ReadFont (
98         const css::uno::Reference<css::container::XHierarchicalNameAccess>& rxTheme,
99         const PresenterTheme::SharedFontDescriptor& rpDefault);
100     static PresenterTheme::SharedFontDescriptor ReadFont (
101         const Reference<beans::XPropertySet>& rxFontProperties,
102         const PresenterTheme::SharedFontDescriptor& rpDefault);
103 
104     std::shared_ptr<PresenterTheme::Theme> ReadTheme (
105         PresenterConfigurationAccess& rConfiguration,
106         const OUString& rsThemeName);
107 
108     static BorderSize ReadBorderSize (const Reference<container::XNameAccess>& rxNode);
109 
110 private:
111     static Any GetByName (
112         const Reference<container::XNameAccess>& rxNode,
113         const OUString& rsName);
114 };
115 
116 /** A PaneStyle describes how a pane is rendered.
117 */
118 class PaneStyle
119 {
120 public:
121     PaneStyle();
122 
123     SharedBitmapDescriptor GetBitmap (const OUString& sBitmapName) const;
124 
125     OUString msStyleName;
126     std::shared_ptr<PaneStyle> mpParentStyle;
127     PresenterTheme::SharedFontDescriptor mpFont;
128     BorderSize maInnerBorderSize;
129     BorderSize maOuterBorderSize;
130     std::shared_ptr<PresenterBitmapContainer> mpBitmaps;
131 
132     PresenterTheme::SharedFontDescriptor GetFont() const;
133 };
134 
135 typedef std::shared_ptr<PaneStyle> SharedPaneStyle;
136 
137 class PaneStyleContainer
138 {
139 private:
140     ::std::vector<SharedPaneStyle> mStyles;
141 
142 public:
143     void Read (
144         const ReadContext& rReadContext,
145         const Reference<container::XHierarchicalNameAccess>& rThemeRoot);
146 
147     SharedPaneStyle GetPaneStyle (const OUString& rsStyleName) const;
148 
149 private:
150     void ProcessPaneStyle (
151         ReadContext const & rReadContext,
152         const ::std::vector<css::uno::Any>& rValues);
153 };
154 
155 /** A ViewStyle describes how a view is displayed.
156 */
157 class ViewStyle
158 {
159 public:
160     ViewStyle();
161 
162     SharedBitmapDescriptor GetBitmap (std::u16string_view sBitmapName) const;
163 
164     PresenterTheme::SharedFontDescriptor GetFont() const;
165 
166     OUString msStyleName;
167     std::shared_ptr<ViewStyle> mpParentStyle;
168     PresenterTheme::SharedFontDescriptor mpFont;
169     SharedBitmapDescriptor mpBackground;
170 };
171 
172 typedef std::shared_ptr<ViewStyle> SharedViewStyle;
173 
174 class ViewStyleContainer
175 {
176 private:
177     ::std::vector<SharedViewStyle> mStyles;
178 
179 public:
180     void Read (
181         const ReadContext& rReadContext,
182         const Reference<container::XHierarchicalNameAccess>& rThemeRoot);
183 
184     SharedViewStyle GetViewStyle (const OUString& rsStyleName) const;
185 
186 private:
187     void ProcessViewStyle(
188         ReadContext const & rReadContext,
189         const Reference<beans::XPropertySet>& rxProperties);
190 };
191 
192 class StyleAssociationContainer
193 {
194 public:
195     void Read (
196         const Reference<container::XHierarchicalNameAccess>& rThemeRoot);
197 
198     OUString GetStyleName (const OUString& rsResourceName) const;
199 
200 private:
201     typedef map<OUString, OUString> StyleAssociations;
202     StyleAssociations maStyleAssociations;
203 
204     void ProcessStyleAssociation(
205         const ::std::vector<css::uno::Any>& rValues);
206 };
207 
208 } // end of anonymous namespace
209 
210 class PresenterTheme::Theme
211 {
212 public:
213     Theme (
214         const Reference<container::XHierarchicalNameAccess>& rThemeRoot,
215         const OUString& rsNodeName);
216 
217     void Read (
218         PresenterConfigurationAccess& rConfiguration,
219         ReadContext& rReadContext);
220 
221     OUString msConfigurationNodeName;
222     std::shared_ptr<Theme> mpParentTheme;
223     SharedBitmapDescriptor mpBackground;
224     PaneStyleContainer maPaneStyles;
225     ViewStyleContainer maViewStyles;
226     StyleAssociationContainer maStyleAssociations;
227     Reference<container::XHierarchicalNameAccess> mxThemeRoot;
228     std::shared_ptr<PresenterBitmapContainer> mpIconContainer;
229     typedef map<OUString,SharedFontDescriptor> FontContainer;
230     FontContainer maFontContainer;
231 
232     SharedPaneStyle GetPaneStyle (const OUString& rsStyleName) const;
233     SharedViewStyle GetViewStyle (const OUString& rsStyleName) const;
234 
235 private:
236     void ProcessFont(
237         const OUString& rsKey,
238         const Reference<beans::XPropertySet>& rxProperties);
239 };
240 
241 //===== PresenterTheme ========================================================
242 
PresenterTheme(const css::uno::Reference<css::uno::XComponentContext> & rxContext,const css::uno::Reference<css::rendering::XCanvas> & rxCanvas)243 PresenterTheme::PresenterTheme (
244     const css::uno::Reference<css::uno::XComponentContext>& rxContext,
245     const css::uno::Reference<css::rendering::XCanvas>& rxCanvas)
246     : mxContext(rxContext),
247       mpTheme(),
248       mxCanvas(rxCanvas)
249 {
250     mpTheme = ReadTheme();
251 }
252 
~PresenterTheme()253 PresenterTheme::~PresenterTheme()
254 {
255 }
256 
ReadTheme()257 std::shared_ptr<PresenterTheme::Theme> PresenterTheme::ReadTheme()
258 {
259     ReadContext aReadContext(mxContext, mxCanvas);
260 
261     PresenterConfigurationAccess aConfiguration (
262         mxContext,
263         "/org.openoffice.Office.PresenterScreen/",
264         PresenterConfigurationAccess::READ_ONLY);
265 
266     return aReadContext.ReadTheme(aConfiguration, OUString());
267 }
268 
HasCanvas() const269 bool PresenterTheme::HasCanvas() const
270 {
271     return mxCanvas.is();
272 }
273 
ProvideCanvas(const Reference<rendering::XCanvas> & rxCanvas)274 void PresenterTheme::ProvideCanvas (const Reference<rendering::XCanvas>& rxCanvas)
275 {
276     if ( ! mxCanvas.is() && rxCanvas.is())
277     {
278         mxCanvas = rxCanvas;
279         ReadTheme();
280     }
281 }
282 
GetStyleName(const OUString & rsResourceURL) const283 OUString PresenterTheme::GetStyleName (const OUString& rsResourceURL) const
284 {
285     OUString sStyleName;
286     std::shared_ptr<Theme> pTheme (mpTheme);
287     while (sStyleName.isEmpty() && pTheme != nullptr)
288     {
289         sStyleName = pTheme->maStyleAssociations.GetStyleName(rsResourceURL);
290         pTheme = pTheme->mpParentTheme;
291     }
292     return sStyleName;
293 }
294 
GetBorderSize(const OUString & rsStyleName,const bool bOuter) const295 ::std::vector<sal_Int32> PresenterTheme::GetBorderSize (
296     const OUString& rsStyleName,
297     const bool bOuter) const
298 {
299     OSL_ASSERT(mpTheme != nullptr);
300 
301     SharedPaneStyle pPaneStyle (mpTheme->GetPaneStyle(rsStyleName));
302     if (pPaneStyle)
303         if (bOuter)
304             return pPaneStyle->maOuterBorderSize.ToVector();
305         else
306             return pPaneStyle->maInnerBorderSize.ToVector();
307     else
308     {
309         return ::std::vector<sal_Int32>(4,0);
310     }
311 }
312 
ReadFont(const Reference<container::XHierarchicalNameAccess> & rxNode,const PresenterTheme::SharedFontDescriptor & rpDefault)313 PresenterTheme::SharedFontDescriptor PresenterTheme::ReadFont (
314     const Reference<container::XHierarchicalNameAccess>& rxNode,
315     const PresenterTheme::SharedFontDescriptor& rpDefault)
316 {
317     return ReadContext::ReadFont(rxNode, rpDefault);
318 }
319 
ConvertToColor(const Any & rColorSequence,sal_uInt32 & rColor)320 bool PresenterTheme::ConvertToColor (
321     const Any& rColorSequence,
322     sal_uInt32& rColor)
323 {
324     Sequence<sal_Int8> aByteSequence;
325     if (rColorSequence >>= aByteSequence)
326     {
327         rColor = std::accumulate(aByteSequence.begin(), aByteSequence.end(), sal_uInt32(0),
328             [](const sal_uInt32 nRes, const sal_uInt8 nByte) { return (nRes << 8) | nByte; });
329         return true;
330     }
331     else
332         return false;
333 }
334 
GetNodeForViewStyle(const OUString & rsStyleName) const335 std::shared_ptr<PresenterConfigurationAccess> PresenterTheme::GetNodeForViewStyle (
336     const OUString& rsStyleName) const
337 {
338     if (mpTheme == nullptr)
339         return std::shared_ptr<PresenterConfigurationAccess>();
340 
341     // Open configuration for writing.
342     auto pConfiguration = std::make_shared<PresenterConfigurationAccess>(
343             mxContext,
344             "/org.openoffice.Office.PresenterScreen/",
345             PresenterConfigurationAccess::READ_WRITE);
346 
347     // Get configuration node for the view style container of the current
348     // theme.
349     if (pConfiguration->GoToChild( OUString(
350         "Presenter/Themes/" + mpTheme->msConfigurationNodeName + "/ViewStyles")))
351     {
352         pConfiguration->GoToChild(
353             [&rsStyleName] (OUString const&, uno::Reference<beans::XPropertySet> const& xProps)
354             {
355                 return PresenterConfigurationAccess::IsStringPropertyEqual(
356                         rsStyleName, "StyleName", xProps);
357             });
358     }
359     return pConfiguration;
360 }
361 
GetBitmap(const OUString & rsStyleName,const OUString & rsBitmapName) const362 SharedBitmapDescriptor PresenterTheme::GetBitmap (
363     const OUString& rsStyleName,
364     const OUString& rsBitmapName) const
365 {
366     if (mpTheme != nullptr)
367     {
368         if (rsStyleName.isEmpty())
369         {
370             if (rsBitmapName == "Background")
371             {
372                 std::shared_ptr<Theme> pTheme (mpTheme);
373                 while (pTheme != nullptr && !pTheme->mpBackground)
374                     pTheme = pTheme->mpParentTheme;
375                 if (pTheme != nullptr)
376                     return pTheme->mpBackground;
377                 else
378                     return SharedBitmapDescriptor();
379             }
380         }
381         else
382         {
383             SharedPaneStyle pPaneStyle (mpTheme->GetPaneStyle(rsStyleName));
384             if (pPaneStyle)
385             {
386                 SharedBitmapDescriptor pBitmap (pPaneStyle->GetBitmap(rsBitmapName));
387                 if (pBitmap)
388                     return pBitmap;
389             }
390 
391             SharedViewStyle pViewStyle (mpTheme->GetViewStyle(rsStyleName));
392             if (pViewStyle)
393             {
394                 SharedBitmapDescriptor pBitmap (pViewStyle->GetBitmap(rsBitmapName));
395                 if (pBitmap)
396                     return pBitmap;
397             }
398         }
399     }
400 
401     return SharedBitmapDescriptor();
402 }
403 
GetBitmap(const OUString & rsBitmapName) const404 SharedBitmapDescriptor PresenterTheme::GetBitmap (
405     const OUString& rsBitmapName) const
406 {
407     if (mpTheme != nullptr)
408     {
409         if (rsBitmapName == "Background")
410         {
411             std::shared_ptr<Theme> pTheme (mpTheme);
412             while (pTheme != nullptr && !pTheme->mpBackground)
413                 pTheme = pTheme->mpParentTheme;
414             if (pTheme != nullptr)
415                 return pTheme->mpBackground;
416             else
417                 return SharedBitmapDescriptor();
418         }
419         else
420         {
421             if (mpTheme->mpIconContainer != nullptr)
422                 return mpTheme->mpIconContainer->GetBitmap(rsBitmapName);
423         }
424     }
425 
426     return SharedBitmapDescriptor();
427 }
428 
GetBitmapContainer() const429 std::shared_ptr<PresenterBitmapContainer> PresenterTheme::GetBitmapContainer() const
430 {
431     if (mpTheme != nullptr)
432         return mpTheme->mpIconContainer;
433     else
434         return std::shared_ptr<PresenterBitmapContainer>();
435 }
436 
GetFont(const OUString & rsStyleName) const437 PresenterTheme::SharedFontDescriptor PresenterTheme::GetFont (
438     const OUString& rsStyleName) const
439 {
440     if (mpTheme != nullptr)
441     {
442         SharedPaneStyle pPaneStyle (mpTheme->GetPaneStyle(rsStyleName));
443         if (pPaneStyle)
444             return pPaneStyle->GetFont();
445 
446         SharedViewStyle pViewStyle (mpTheme->GetViewStyle(rsStyleName));
447         if (pViewStyle)
448             return pViewStyle->GetFont();
449 
450         std::shared_ptr<Theme> pTheme (mpTheme);
451         while (pTheme != nullptr)
452         {
453             Theme::FontContainer::const_iterator iFont (pTheme->maFontContainer.find(rsStyleName));
454             if (iFont != pTheme->maFontContainer.end())
455                 return iFont->second;
456 
457             pTheme = pTheme->mpParentTheme;
458         }
459     }
460 
461     return SharedFontDescriptor();
462 }
463 
464 //===== FontDescriptor ========================================================
465 
FontDescriptor(const std::shared_ptr<FontDescriptor> & rpDescriptor)466 PresenterTheme::FontDescriptor::FontDescriptor (
467     const std::shared_ptr<FontDescriptor>& rpDescriptor)
468     : msFamilyName(),
469       msStyleName(),
470       mnSize(12),
471       mnColor(0x00000000),
472       msAnchor(OUString("Left")),
473       mnXOffset(0),
474       mnYOffset(0)
475 {
476     if (rpDescriptor != nullptr)
477     {
478         msFamilyName = rpDescriptor->msFamilyName;
479         msStyleName = rpDescriptor->msStyleName;
480         mnSize = rpDescriptor->mnSize;
481         mnColor = rpDescriptor->mnColor;
482         msAnchor = rpDescriptor->msAnchor;
483         mnXOffset = rpDescriptor->mnXOffset;
484         mnYOffset = rpDescriptor->mnYOffset;
485     }
486 }
487 
PrepareFont(const Reference<rendering::XCanvas> & rxCanvas)488 bool PresenterTheme::FontDescriptor::PrepareFont (
489     const Reference<rendering::XCanvas>& rxCanvas)
490 {
491     if (mxFont.is())
492         return true;
493 
494     if ( ! rxCanvas.is())
495         return false;
496 
497     const double nCellSize (GetCellSizeForDesignSize(rxCanvas, mnSize));
498     mxFont = CreateFont(rxCanvas, nCellSize);
499 
500     return mxFont.is();
501 }
502 
CreateFont(const Reference<rendering::XCanvas> & rxCanvas,const double nCellSize) const503 Reference<rendering::XCanvasFont> PresenterTheme::FontDescriptor::CreateFont (
504     const Reference<rendering::XCanvas>& rxCanvas,
505     const double nCellSize) const
506 {
507     rendering::FontRequest aFontRequest;
508     aFontRequest.FontDescription.FamilyName = msFamilyName;
509     if (msFamilyName.isEmpty())
510         aFontRequest.FontDescription.FamilyName = "Tahoma";
511     aFontRequest.FontDescription.StyleName = msStyleName;
512     aFontRequest.CellSize = nCellSize;
513 
514     // Make an attempt at translating the style name(s)into a corresponding
515     // font description.
516     if (msStyleName == "Bold")
517         aFontRequest.FontDescription.FontDescription.Weight = rendering::PanoseWeight::HEAVY;
518 
519     return rxCanvas->createFont(
520         aFontRequest,
521         Sequence<beans::PropertyValue>(),
522         geometry::Matrix2D(1,0,0,1));
523 }
524 
GetCellSizeForDesignSize(const Reference<rendering::XCanvas> & rxCanvas,const double nDesignSize) const525 double PresenterTheme::FontDescriptor::GetCellSizeForDesignSize (
526     const Reference<rendering::XCanvas>& rxCanvas,
527     const double nDesignSize) const
528 {
529     // Use the given design size as initial value in calculating the cell
530     // size.
531     double nCellSize (nDesignSize);
532 
533     if ( ! rxCanvas.is())
534     {
535         // We need the canvas to do the conversion.  Return the design size,
536         // it is the our best guess in this circumstance.
537         return nDesignSize;
538     }
539 
540     Reference<rendering::XCanvasFont> xFont (CreateFont(rxCanvas, nCellSize));
541     if ( ! xFont.is())
542         return nDesignSize;
543 
544     geometry::RealRectangle2D aBox (PresenterCanvasHelper::GetTextBoundingBox (xFont, "X"));
545 
546     const double nAscent (-aBox.Y1);
547     //tdf#112408
548     if (nAscent == 0)
549         return nDesignSize;
550     const double nDescent (aBox.Y2);
551     const double nScale = (nAscent+nDescent) / nAscent;
552     return nDesignSize * nScale;
553 }
554 
555 //===== Theme =================================================================
556 
Theme(const Reference<container::XHierarchicalNameAccess> & rxThemeRoot,const OUString & rsNodeName)557 PresenterTheme::Theme::Theme (
558     const Reference<container::XHierarchicalNameAccess>& rxThemeRoot,
559     const OUString& rsNodeName)
560     : msConfigurationNodeName(rsNodeName),
561       mpParentTheme(),
562       maPaneStyles(),
563       maViewStyles(),
564       maStyleAssociations(),
565       mxThemeRoot(rxThemeRoot),
566       mpIconContainer()
567 {
568 }
569 
Read(PresenterConfigurationAccess & rConfiguration,ReadContext & rReadContext)570 void PresenterTheme::Theme::Read (
571     PresenterConfigurationAccess& rConfiguration,
572     ReadContext& rReadContext)
573 {
574     // Parent theme name.
575     OUString sParentThemeName;
576     if ((PresenterConfigurationAccess::GetConfigurationNode(mxThemeRoot, "ParentTheme")
577             >>= sParentThemeName)
578         && !sParentThemeName.isEmpty())
579     {
580         mpParentTheme = rReadContext.ReadTheme(rConfiguration, sParentThemeName);
581     }
582 
583     // Background.
584     mpBackground = PresenterBitmapContainer::LoadBitmap(
585         mxThemeRoot,
586         "Background",
587         rReadContext.mxPresenterHelper,
588         rReadContext.mxCanvas,
589         SharedBitmapDescriptor());
590 
591     // Style associations.
592     maStyleAssociations.Read(mxThemeRoot);
593 
594     // Pane styles.
595     maPaneStyles.Read(rReadContext, mxThemeRoot);
596 
597     // View styles.
598     maViewStyles.Read(rReadContext, mxThemeRoot);
599 
600     // Read bitmaps.
601     mpIconContainer = std::make_shared<PresenterBitmapContainer>(
602         Reference<container::XNameAccess>(
603             PresenterConfigurationAccess::GetConfigurationNode(mxThemeRoot, "Bitmaps"), UNO_QUERY),
604         mpParentTheme != nullptr ? mpParentTheme->mpIconContainer
605                                  : std::shared_ptr<PresenterBitmapContainer>(),
606         rReadContext.mxComponentContext, rReadContext.mxCanvas);
607 
608     // Read fonts.
609     Reference<container::XNameAccess> xFontNode(
610         PresenterConfigurationAccess::GetConfigurationNode(mxThemeRoot, "Fonts"),
611         UNO_QUERY);
612     PresenterConfigurationAccess::ForAll(
613         xFontNode,
614         [this] (OUString const& rKey, uno::Reference<beans::XPropertySet> const& xProps)
615         {
616             return this->ProcessFont(rKey, xProps);
617         });
618 }
619 
GetPaneStyle(const OUString & rsStyleName) const620 SharedPaneStyle PresenterTheme::Theme::GetPaneStyle (const OUString& rsStyleName) const
621 {
622     SharedPaneStyle pPaneStyle (maPaneStyles.GetPaneStyle(rsStyleName));
623     if (pPaneStyle)
624         return pPaneStyle;
625     else if (mpParentTheme != nullptr)
626         return mpParentTheme->GetPaneStyle(rsStyleName);
627     else
628         return SharedPaneStyle();
629 }
630 
GetViewStyle(const OUString & rsStyleName) const631 SharedViewStyle PresenterTheme::Theme::GetViewStyle (const OUString& rsStyleName) const
632 {
633     SharedViewStyle pViewStyle (maViewStyles.GetViewStyle(rsStyleName));
634     if (pViewStyle)
635         return pViewStyle;
636     else if (mpParentTheme != nullptr)
637         return mpParentTheme->GetViewStyle(rsStyleName);
638     else
639         return SharedViewStyle();
640 }
641 
ProcessFont(const OUString & rsKey,const Reference<beans::XPropertySet> & rxProperties)642 void PresenterTheme::Theme::ProcessFont(
643     const OUString& rsKey,
644     const Reference<beans::XPropertySet>& rxProperties)
645 {
646     maFontContainer[rsKey] = ReadContext::ReadFont(rxProperties, SharedFontDescriptor());
647 }
648 
649 namespace {
650 
651 //===== ReadContext ===========================================================
652 
ReadContext(const css::uno::Reference<css::uno::XComponentContext> & rxContext,const Reference<rendering::XCanvas> & rxCanvas)653 ReadContext::ReadContext (
654     const css::uno::Reference<css::uno::XComponentContext>& rxContext,
655     const Reference<rendering::XCanvas>& rxCanvas)
656     : mxComponentContext(rxContext),
657       mxCanvas(rxCanvas),
658       mxPresenterHelper()
659 {
660     Reference<lang::XMultiComponentFactory> xFactory (rxContext->getServiceManager());
661     if (xFactory.is())
662     {
663         mxPresenterHelper.set(
664             xFactory->createInstanceWithContext(
665                 "com.sun.star.comp.Draw.PresenterHelper",
666                 rxContext),
667             UNO_QUERY_THROW);
668     }
669 }
670 
ReadFont(const Reference<container::XHierarchicalNameAccess> & rxNode,const PresenterTheme::SharedFontDescriptor & rpDefault)671 PresenterTheme::SharedFontDescriptor ReadContext::ReadFont (
672     const Reference<container::XHierarchicalNameAccess>& rxNode,
673     const PresenterTheme::SharedFontDescriptor& rpDefault)
674 {
675     if ( ! rxNode.is())
676         return PresenterTheme::SharedFontDescriptor();
677 
678     try
679     {
680         Reference<container::XHierarchicalNameAccess> xFont (
681             PresenterConfigurationAccess::GetConfigurationNode(
682                 rxNode,
683                 /*rsFontPath*/""),
684                 UNO_QUERY_THROW);
685 
686         Reference<beans::XPropertySet> xProperties (xFont, UNO_QUERY_THROW);
687         return ReadFont(xProperties, rpDefault);
688     }
689     catch (Exception&)
690     {
691         OSL_ASSERT(false);
692     }
693 
694     return PresenterTheme::SharedFontDescriptor();
695 }
696 
ReadFont(const Reference<beans::XPropertySet> & rxProperties,const PresenterTheme::SharedFontDescriptor & rpDefault)697 PresenterTheme::SharedFontDescriptor ReadContext::ReadFont (
698     const Reference<beans::XPropertySet>& rxProperties,
699     const PresenterTheme::SharedFontDescriptor& rpDefault)
700 {
701     auto pDescriptor = std::make_shared<PresenterTheme::FontDescriptor>(rpDefault);
702 
703     PresenterConfigurationAccess::GetProperty(rxProperties, "FamilyName") >>= pDescriptor->msFamilyName;
704     PresenterConfigurationAccess::GetProperty(rxProperties, "Style") >>= pDescriptor->msStyleName;
705     PresenterConfigurationAccess::GetProperty(rxProperties, "Size") >>= pDescriptor->mnSize;
706     PresenterTheme::ConvertToColor(
707         PresenterConfigurationAccess::GetProperty(rxProperties, "Color"),
708         pDescriptor->mnColor);
709     PresenterConfigurationAccess::GetProperty(rxProperties, "Anchor") >>= pDescriptor->msAnchor;
710     PresenterConfigurationAccess::GetProperty(rxProperties, "XOffset") >>= pDescriptor->mnXOffset;
711     PresenterConfigurationAccess::GetProperty(rxProperties, "YOffset") >>= pDescriptor->mnYOffset;
712 
713     return pDescriptor;
714 }
715 
GetByName(const Reference<container::XNameAccess> & rxNode,const OUString & rsName)716 Any ReadContext::GetByName (
717     const Reference<container::XNameAccess>& rxNode,
718     const OUString& rsName)
719 {
720     OSL_ASSERT(rxNode.is());
721     if (rxNode->hasByName(rsName))
722         return rxNode->getByName(rsName);
723     else
724         return Any();
725 }
726 
ReadTheme(PresenterConfigurationAccess & rConfiguration,const OUString & rsThemeName)727 std::shared_ptr<PresenterTheme::Theme> ReadContext::ReadTheme (
728     PresenterConfigurationAccess& rConfiguration,
729     const OUString& rsThemeName)
730 {
731     std::shared_ptr<PresenterTheme::Theme> pTheme;
732 
733     OUString sCurrentThemeName (rsThemeName);
734     if (sCurrentThemeName.isEmpty())
735     {
736          // No theme name given.  Look up the CurrentTheme property.
737          rConfiguration.GetConfigurationNode("Presenter/CurrentTheme") >>= sCurrentThemeName;
738          if (sCurrentThemeName.isEmpty())
739          {
740              // Still no name.  Use "DefaultTheme".
741              sCurrentThemeName = "DefaultTheme";
742          }
743     }
744 
745     Reference<container::XNameAccess> xThemes (
746         rConfiguration.GetConfigurationNode("Presenter/Themes"),
747         UNO_QUERY);
748     if (xThemes.is())
749     {
750         // Iterate over all themes and search the one with the given name.
751         const Sequence<OUString> aKeys (xThemes->getElementNames());
752         for (const OUString& rsKey : aKeys)
753         {
754             Reference<container::XHierarchicalNameAccess> xTheme (
755                 xThemes->getByName(rsKey), UNO_QUERY);
756             if (xTheme.is())
757             {
758                 OUString sThemeName;
759                 PresenterConfigurationAccess::GetConfigurationNode(xTheme, "ThemeName")
760                     >>= sThemeName;
761                 if (sThemeName == sCurrentThemeName)
762                 {
763                     pTheme = std::make_shared<PresenterTheme::Theme>(xTheme,rsKey);
764                     break;
765                 }
766             }
767         }
768     }
769 
770     if (pTheme != nullptr)
771     {
772         pTheme->Read(rConfiguration, *this);
773     }
774 
775     return pTheme;
776 }
777 
ReadBorderSize(const Reference<container::XNameAccess> & rxNode)778 BorderSize ReadContext::ReadBorderSize (const Reference<container::XNameAccess>& rxNode)
779 {
780     BorderSize aBorderSize;
781 
782     if (rxNode.is())
783     {
784         GetByName(rxNode, "Left") >>= aBorderSize.mnLeft;
785         GetByName(rxNode, "Top") >>= aBorderSize.mnTop;
786         GetByName(rxNode, "Right") >>= aBorderSize.mnRight;
787         GetByName(rxNode, "Bottom") >>= aBorderSize.mnBottom;
788     }
789 
790     return aBorderSize;
791 }
792 
793 //===== PaneStyleContainer ====================================================
794 
Read(const ReadContext & rReadContext,const Reference<container::XHierarchicalNameAccess> & rxThemeRoot)795 void PaneStyleContainer::Read (
796     const ReadContext& rReadContext,
797     const Reference<container::XHierarchicalNameAccess>& rxThemeRoot)
798 {
799     Reference<container::XNameAccess> xPaneStyleList (
800         PresenterConfigurationAccess::GetConfigurationNode(
801             rxThemeRoot,
802             "PaneStyles"),
803         UNO_QUERY);
804     if (!xPaneStyleList.is())
805         return;
806 
807     ::std::vector<OUString> aProperties;
808     aProperties.reserve(6);
809     aProperties.emplace_back("StyleName");
810     aProperties.emplace_back("ParentStyle");
811     aProperties.emplace_back("TitleFont");
812     aProperties.emplace_back("InnerBorderSize");
813     aProperties.emplace_back("OuterBorderSize");
814     aProperties.emplace_back("BorderBitmapList");
815     PresenterConfigurationAccess::ForAll(
816         xPaneStyleList,
817         aProperties,
818         [this, &rReadContext] (std::vector<uno::Any> const& rValues)
819         {
820             return this->ProcessPaneStyle(rReadContext, rValues);
821         });
822 }
823 
ProcessPaneStyle(ReadContext const & rReadContext,const::std::vector<Any> & rValues)824 void PaneStyleContainer::ProcessPaneStyle(
825     ReadContext const & rReadContext,
826     const ::std::vector<Any>& rValues)
827 {
828     if (rValues.size() != 6)
829         return;
830 
831     auto pStyle = std::make_shared<PaneStyle>();
832 
833     rValues[0] >>= pStyle->msStyleName;
834 
835     OUString sParentStyleName;
836     if (rValues[1] >>= sParentStyleName)
837     {
838         // Find parent style.
839         auto iStyle = std::find_if(mStyles.begin(), mStyles.end(),
840             [&sParentStyleName](const SharedPaneStyle& rxStyle) { return rxStyle->msStyleName == sParentStyleName; });
841         if (iStyle != mStyles.end())
842             pStyle->mpParentStyle = *iStyle;
843     }
844 
845     Reference<container::XHierarchicalNameAccess> xFontNode (rValues[2], UNO_QUERY);
846     pStyle->mpFont = ReadContext::ReadFont(
847         xFontNode, PresenterTheme::SharedFontDescriptor());
848 
849     Reference<container::XNameAccess> xInnerBorderSizeNode (rValues[3], UNO_QUERY);
850     pStyle->maInnerBorderSize = ReadContext::ReadBorderSize(xInnerBorderSizeNode);
851     Reference<container::XNameAccess> xOuterBorderSizeNode (rValues[4], UNO_QUERY);
852     pStyle->maOuterBorderSize = ReadContext::ReadBorderSize(xOuterBorderSizeNode);
853 
854     if (pStyle->mpParentStyle != nullptr)
855     {
856         pStyle->maInnerBorderSize.Merge(pStyle->mpParentStyle->maInnerBorderSize);
857         pStyle->maOuterBorderSize.Merge(pStyle->mpParentStyle->maOuterBorderSize);
858     }
859 
860     if (rReadContext.mxCanvas.is())
861     {
862         Reference<container::XNameAccess> xBitmapsNode (rValues[5], UNO_QUERY);
863         pStyle->mpBitmaps = std::make_shared<PresenterBitmapContainer>(
864             xBitmapsNode,
865             pStyle->mpParentStyle != nullptr ? pStyle->mpParentStyle->mpBitmaps
866                                              : std::shared_ptr<PresenterBitmapContainer>(),
867             rReadContext.mxComponentContext, rReadContext.mxCanvas,
868             rReadContext.mxPresenterHelper);
869     }
870 
871     mStyles.push_back(pStyle);
872 }
873 
GetPaneStyle(const OUString & rsStyleName) const874 SharedPaneStyle PaneStyleContainer::GetPaneStyle (const OUString& rsStyleName) const
875 {
876     auto iStyle = std::find_if(mStyles.begin(), mStyles.end(),
877         [&rsStyleName](const SharedPaneStyle& rxStyle) { return rxStyle->msStyleName == rsStyleName; });
878     if (iStyle != mStyles.end())
879         return *iStyle;
880     return SharedPaneStyle();
881 }
882 
883 //===== PaneStyle =============================================================
884 
PaneStyle()885 PaneStyle::PaneStyle()
886     : msStyleName(),
887       mpParentStyle(),
888       mpFont(),
889       maInnerBorderSize(),
890       maOuterBorderSize(),
891       mpBitmaps()
892 {
893 }
894 
GetBitmap(const OUString & rsBitmapName) const895 SharedBitmapDescriptor PaneStyle::GetBitmap (const OUString& rsBitmapName) const
896 {
897     if (mpBitmaps != nullptr)
898     {
899         SharedBitmapDescriptor pBitmap = mpBitmaps->GetBitmap(rsBitmapName);
900         if (pBitmap)
901             return pBitmap;
902     }
903 
904     if (mpParentStyle != nullptr)
905         return mpParentStyle->GetBitmap(rsBitmapName);
906     else
907         return SharedBitmapDescriptor();
908 }
909 
GetFont() const910 PresenterTheme::SharedFontDescriptor PaneStyle::GetFont() const
911 {
912     if (mpFont)
913         return mpFont;
914     else if (mpParentStyle != nullptr)
915         return mpParentStyle->GetFont();
916     else
917         return PresenterTheme::SharedFontDescriptor();
918 }
919 
920 //===== ViewStyleContainer ====================================================
921 
Read(const ReadContext & rReadContext,const Reference<container::XHierarchicalNameAccess> & rxThemeRoot)922 void ViewStyleContainer::Read (
923     const ReadContext& rReadContext,
924     const Reference<container::XHierarchicalNameAccess>& rxThemeRoot)
925 {
926     Reference<container::XNameAccess> xViewStyleList (
927         PresenterConfigurationAccess::GetConfigurationNode(
928             rxThemeRoot,
929             "ViewStyles"),
930         UNO_QUERY);
931     if (xViewStyleList.is())
932     {
933         PresenterConfigurationAccess::ForAll(
934             xViewStyleList,
935             [this, &rReadContext] (OUString const&, uno::Reference<beans::XPropertySet> const& xProps)
936             {
937                 return this->ProcessViewStyle(rReadContext, xProps);
938             });
939     }
940 }
941 
ProcessViewStyle(ReadContext const & rReadContext,const Reference<beans::XPropertySet> & rxProperties)942 void ViewStyleContainer::ProcessViewStyle(
943     ReadContext const & rReadContext,
944     const Reference<beans::XPropertySet>& rxProperties)
945 {
946     auto pStyle = std::make_shared<ViewStyle>();
947 
948     PresenterConfigurationAccess::GetProperty(rxProperties, "StyleName")
949         >>= pStyle->msStyleName;
950 
951     OUString sParentStyleName;
952     if (PresenterConfigurationAccess::GetProperty(rxProperties, "ParentStyle")
953         >>= sParentStyleName)
954     {
955         // Find parent style.
956         auto iStyle = std::find_if(mStyles.begin(), mStyles.end(),
957             [&sParentStyleName](const SharedViewStyle& rxStyle) { return rxStyle->msStyleName == sParentStyleName; });
958         if (iStyle != mStyles.end())
959         {
960             pStyle->mpParentStyle = *iStyle;
961             pStyle->mpFont = (*iStyle)->mpFont;
962             pStyle->mpBackground = (*iStyle)->mpBackground;
963         }
964     }
965 
966     Reference<container::XHierarchicalNameAccess> xFontNode (
967         PresenterConfigurationAccess::GetProperty(rxProperties, "Font"), UNO_QUERY);
968     PresenterTheme::SharedFontDescriptor pFont (
969         ReadContext::ReadFont(xFontNode, PresenterTheme::SharedFontDescriptor()));
970     if (pFont)
971         pStyle->mpFont = pFont;
972 
973     Reference<container::XHierarchicalNameAccess> xBackgroundNode (
974         PresenterConfigurationAccess::GetProperty(rxProperties, "Background"),
975         UNO_QUERY);
976     SharedBitmapDescriptor pBackground (PresenterBitmapContainer::LoadBitmap(
977         xBackgroundNode,
978         OUString(),
979         rReadContext.mxPresenterHelper,
980         rReadContext.mxCanvas,
981         SharedBitmapDescriptor()));
982     if (pBackground && pBackground->GetNormalBitmap().is())
983         pStyle->mpBackground = pBackground;
984 
985     mStyles.push_back(pStyle);
986 }
987 
GetViewStyle(const OUString & rsStyleName) const988 SharedViewStyle ViewStyleContainer::GetViewStyle (const OUString& rsStyleName) const
989 {
990     auto iStyle = std::find_if(mStyles.begin(), mStyles.end(),
991         [&rsStyleName](const SharedViewStyle& rxStyle) { return rxStyle->msStyleName == rsStyleName; });
992     if (iStyle != mStyles.end())
993         return *iStyle;
994     return SharedViewStyle();
995 }
996 
997 //===== ViewStyle =============================================================
998 
ViewStyle()999 ViewStyle::ViewStyle()
1000     : msStyleName(),
1001       mpParentStyle(),
1002       mpFont(),
1003       mpBackground()
1004 {
1005 }
1006 
GetBitmap(std::u16string_view rsBitmapName) const1007 SharedBitmapDescriptor ViewStyle::GetBitmap (std::u16string_view rsBitmapName) const
1008 {
1009     if (rsBitmapName == u"Background")
1010         return mpBackground;
1011     else
1012         return SharedBitmapDescriptor();
1013 }
1014 
GetFont() const1015 PresenterTheme::SharedFontDescriptor ViewStyle::GetFont() const
1016 {
1017     if (mpFont)
1018         return mpFont;
1019     else if (mpParentStyle != nullptr)
1020         return mpParentStyle->GetFont();
1021     else
1022         return PresenterTheme::SharedFontDescriptor();
1023 }
1024 
1025 //===== StyleAssociationContainer =============================================
1026 
Read(const Reference<container::XHierarchicalNameAccess> & rxThemeRoot)1027 void StyleAssociationContainer::Read (
1028     const Reference<container::XHierarchicalNameAccess>& rxThemeRoot)
1029 {
1030     Reference<container::XNameAccess> xStyleAssociationList (
1031         PresenterConfigurationAccess::GetConfigurationNode(
1032             rxThemeRoot,
1033             "StyleAssociations"),
1034         UNO_QUERY);
1035     if (!xStyleAssociationList.is())
1036         return;
1037 
1038     ::std::vector<OUString> aProperties { "ResourceURL", "StyleName" };
1039     PresenterConfigurationAccess::ForAll(
1040         xStyleAssociationList,
1041         aProperties,
1042         [this] (std::vector<uno::Any> const& rValues)
1043         {
1044             return this->ProcessStyleAssociation(rValues);
1045         });
1046 }
1047 
GetStyleName(const OUString & rsResourceName) const1048 OUString StyleAssociationContainer::GetStyleName (const OUString& rsResourceName) const
1049 {
1050     StyleAssociations::const_iterator iAssociation (maStyleAssociations.find(rsResourceName));
1051     if (iAssociation != maStyleAssociations.end())
1052         return iAssociation->second;
1053     else
1054         return OUString();
1055 }
1056 
ProcessStyleAssociation(const::std::vector<Any> & rValues)1057 void StyleAssociationContainer::ProcessStyleAssociation(
1058     const ::std::vector<Any>& rValues)
1059 {
1060     if (rValues.size() != 2)
1061         return;
1062 
1063     OUString sResourceURL;
1064     OUString sStyleName;
1065     if ((rValues[0] >>= sResourceURL)
1066         && (rValues[1] >>= sStyleName))
1067     {
1068         maStyleAssociations[sResourceURL] = sStyleName;
1069     }
1070 }
1071 
1072 } // end of anonymous namespace
1073 
1074 } // end of namespace ::sdext::presenter
1075 
1076 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1077