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 <sal/config.h>
21 
22 #include <algorithm>
23 
24 #include "PresenterUIPainter.hxx"
25 
26 #include "PresenterGeometryHelper.hxx"
27 #include <com/sun/star/rendering/CompositeOperation.hpp>
28 
29 using namespace ::com::sun::star;
30 using namespace ::com::sun::star::uno;
31 
32 namespace sdext { namespace presenter {
33 
PaintHorizontalBitmapComposite(const css::uno::Reference<css::rendering::XCanvas> & rxCanvas,const css::awt::Rectangle & rRepaintBox,const css::awt::Rectangle & rBoundingBox,const css::uno::Reference<css::rendering::XBitmap> & rxLeftBitmap,const css::uno::Reference<css::rendering::XBitmap> & rxRepeatableCenterBitmap,const css::uno::Reference<css::rendering::XBitmap> & rxRightBitmap)34 void PresenterUIPainter::PaintHorizontalBitmapComposite (
35     const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
36     const css::awt::Rectangle& rRepaintBox,
37     const css::awt::Rectangle& rBoundingBox,
38     const css::uno::Reference<css::rendering::XBitmap>& rxLeftBitmap,
39     const css::uno::Reference<css::rendering::XBitmap>& rxRepeatableCenterBitmap,
40     const css::uno::Reference<css::rendering::XBitmap>& rxRightBitmap)
41 {
42     if (PresenterGeometryHelper::AreRectanglesDisjoint(rRepaintBox, rBoundingBox))
43     {
44         // The bounding box lies completely outside the repaint area.
45         // Nothing has to be repainted.
46         return;
47     }
48 
49     // Get bitmap sizes.
50     geometry::IntegerSize2D aLeftBitmapSize;
51     if (rxLeftBitmap.is())
52         aLeftBitmapSize = rxLeftBitmap->getSize();
53     geometry::IntegerSize2D aCenterBitmapSize;
54     if (rxRepeatableCenterBitmap.is())
55         aCenterBitmapSize = rxRepeatableCenterBitmap->getSize();
56     geometry::IntegerSize2D aRightBitmapSize;
57     if (rxRightBitmap.is())
58         aRightBitmapSize = rxRightBitmap->getSize();
59 
60     // Prepare painting.
61     rendering::ViewState aViewState (
62         geometry::AffineMatrix2D(1,0,0, 0,1,0),
63         nullptr);
64 
65     rendering::RenderState aRenderState (
66         geometry::AffineMatrix2D(1,0,0, 0,1,0),
67         nullptr,
68         Sequence<double>(4),
69         rendering::CompositeOperation::SOURCE);
70 
71     // Paint the left bitmap once.
72     if (rxLeftBitmap.is())
73     {
74         const awt::Rectangle aLeftBoundingBox (
75             rBoundingBox.X,
76             rBoundingBox.Y,
77             ::std::min(aLeftBitmapSize.Width, rBoundingBox.Width),
78             rBoundingBox.Height);
79         aViewState.Clip.set(
80             PresenterGeometryHelper::CreatePolygon(
81                 PresenterGeometryHelper::Intersection(rRepaintBox, aLeftBoundingBox),
82                 rxCanvas->getDevice()));
83         aRenderState.AffineTransform.m02 = aLeftBoundingBox.X;
84         aRenderState.AffineTransform.m12
85             = aLeftBoundingBox.Y + (aLeftBoundingBox.Height - aLeftBitmapSize.Height) / 2;
86         rxCanvas->drawBitmap(rxLeftBitmap, aViewState, aRenderState);
87     }
88 
89     // Paint the right bitmap once.
90     if (rxRightBitmap.is())
91     {
92         const awt::Rectangle aRightBoundingBox (
93             rBoundingBox.X + rBoundingBox.Width - aRightBitmapSize.Width,
94             rBoundingBox.Y,
95             ::std::min(aRightBitmapSize.Width, rBoundingBox.Width),
96             rBoundingBox.Height);
97         aViewState.Clip.set(
98             PresenterGeometryHelper::CreatePolygon(
99                 PresenterGeometryHelper::Intersection(rRepaintBox, aRightBoundingBox),
100                 rxCanvas->getDevice()));
101         aRenderState.AffineTransform.m02
102             = aRightBoundingBox.X + aRightBoundingBox.Width - aRightBitmapSize.Width;
103         aRenderState.AffineTransform.m12
104             = aRightBoundingBox.Y + (aRightBoundingBox.Height - aRightBitmapSize.Height) / 2;
105         rxCanvas->drawBitmap(rxRightBitmap, aViewState, aRenderState);
106     }
107 
108     // Paint the center bitmap to fill the remaining space.
109     if (!rxRepeatableCenterBitmap.is())
110         return;
111 
112     const awt::Rectangle aCenterBoundingBox (
113         rBoundingBox.X + aLeftBitmapSize.Width,
114         rBoundingBox.Y,
115         rBoundingBox.Width - aLeftBitmapSize.Width - aRightBitmapSize.Width,
116         rBoundingBox.Height);
117     if (aCenterBoundingBox.Width <= 0)
118         return;
119 
120     aViewState.Clip.set(
121         PresenterGeometryHelper::CreatePolygon(
122             PresenterGeometryHelper::Intersection(rRepaintBox, aCenterBoundingBox),
123             rxCanvas->getDevice()));
124     sal_Int32 nX (aCenterBoundingBox.X);
125     const sal_Int32 nRight (aCenterBoundingBox.X + aCenterBoundingBox.Width - 1);
126     aRenderState.AffineTransform.m12
127         = aCenterBoundingBox.Y + (aCenterBoundingBox.Height-aCenterBitmapSize.Height) / 2;
128     while(nX <= nRight)
129     {
130         aRenderState.AffineTransform.m02 = nX;
131         rxCanvas->drawBitmap(rxRepeatableCenterBitmap, aViewState, aRenderState);
132         nX += aCenterBitmapSize.Width;
133     }
134 }
135 
PaintVerticalBitmapComposite(const css::uno::Reference<css::rendering::XCanvas> & rxCanvas,const css::awt::Rectangle & rRepaintBox,const css::awt::Rectangle & rBoundingBox,const css::uno::Reference<css::rendering::XBitmap> & rxTopBitmap,const css::uno::Reference<css::rendering::XBitmap> & rxRepeatableCenterBitmap,const css::uno::Reference<css::rendering::XBitmap> & rxBottomBitmap)136 void PresenterUIPainter::PaintVerticalBitmapComposite (
137     const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
138     const css::awt::Rectangle& rRepaintBox,
139     const css::awt::Rectangle& rBoundingBox,
140     const css::uno::Reference<css::rendering::XBitmap>& rxTopBitmap,
141     const css::uno::Reference<css::rendering::XBitmap>& rxRepeatableCenterBitmap,
142     const css::uno::Reference<css::rendering::XBitmap>& rxBottomBitmap)
143 {
144     if (PresenterGeometryHelper::AreRectanglesDisjoint(rRepaintBox, rBoundingBox))
145     {
146         // The bounding box lies completely outside the repaint area.
147         // Nothing has to be repainted.
148         return;
149     }
150 
151     // Get bitmap sizes.
152     geometry::IntegerSize2D aTopBitmapSize;
153     if (rxTopBitmap.is())
154         aTopBitmapSize = rxTopBitmap->getSize();
155     geometry::IntegerSize2D aCenterBitmapSize;
156     if (rxRepeatableCenterBitmap.is())
157         aCenterBitmapSize = rxRepeatableCenterBitmap->getSize();
158     geometry::IntegerSize2D aBottomBitmapSize;
159     if (rxBottomBitmap.is())
160         aBottomBitmapSize = rxBottomBitmap->getSize();
161 
162     // Prepare painting.
163     rendering::ViewState aViewState (
164         geometry::AffineMatrix2D(1,0,0, 0,1,0),
165         nullptr);
166 
167     rendering::RenderState aRenderState (
168         geometry::AffineMatrix2D(1,0,0, 0,1,0),
169         nullptr,
170         Sequence<double>(4),
171         rendering::CompositeOperation::SOURCE);
172 
173     // Paint the top bitmap once.
174     if (rxTopBitmap.is())
175     {
176         const awt::Rectangle aTopBoundingBox (
177             rBoundingBox.X,
178             rBoundingBox.Y,
179             rBoundingBox.Width,
180             ::std::min(aTopBitmapSize.Height, rBoundingBox.Height));
181         aViewState.Clip.set(
182             PresenterGeometryHelper::CreatePolygon(
183                 PresenterGeometryHelper::Intersection(rRepaintBox, aTopBoundingBox),
184                 rxCanvas->getDevice()));
185         aRenderState.AffineTransform.m02
186             = aTopBoundingBox.X + (aTopBoundingBox.Width - aTopBitmapSize.Width) / 2;
187         aRenderState.AffineTransform.m12 = aTopBoundingBox.Y;
188         rxCanvas->drawBitmap(rxTopBitmap, aViewState, aRenderState);
189     }
190 
191     // Paint the bottom bitmap once.
192     if (rxBottomBitmap.is())
193     {
194         const sal_Int32 nBBoxHeight (::std::min(aBottomBitmapSize.Height, rBoundingBox.Height));
195         const awt::Rectangle aBottomBoundingBox (
196             rBoundingBox.X,
197             rBoundingBox.Y  + rBoundingBox.Height - nBBoxHeight,
198             rBoundingBox.Width,
199             nBBoxHeight);
200         aViewState.Clip.set(
201             PresenterGeometryHelper::CreatePolygon(
202                 PresenterGeometryHelper::Intersection(rRepaintBox, aBottomBoundingBox),
203                 rxCanvas->getDevice()));
204         aRenderState.AffineTransform.m02
205             = aBottomBoundingBox.X + (aBottomBoundingBox.Width - aBottomBitmapSize.Width) / 2;
206         aRenderState.AffineTransform.m12
207             = aBottomBoundingBox.Y + aBottomBoundingBox.Height - aBottomBitmapSize.Height;
208         rxCanvas->drawBitmap(rxBottomBitmap, aViewState, aRenderState);
209     }
210 
211     // Paint the center bitmap to fill the remaining space.
212     if (!rxRepeatableCenterBitmap.is())
213         return;
214 
215     const awt::Rectangle aCenterBoundingBox (
216         rBoundingBox.X,
217         rBoundingBox.Y + aTopBitmapSize.Height,
218         rBoundingBox.Width,
219         rBoundingBox.Height - aTopBitmapSize.Height - aBottomBitmapSize.Height);
220     if (aCenterBoundingBox.Height <= 0)
221         return;
222 
223     aViewState.Clip.set(
224         PresenterGeometryHelper::CreatePolygon(
225             PresenterGeometryHelper::Intersection(rRepaintBox, aCenterBoundingBox),
226             rxCanvas->getDevice()));
227     sal_Int32 nY (aCenterBoundingBox.Y);
228     const sal_Int32 nBottom (aCenterBoundingBox.Y + aCenterBoundingBox.Height - 1);
229     aRenderState.AffineTransform.m02
230         = aCenterBoundingBox.X + (aCenterBoundingBox.Width-aCenterBitmapSize.Width) / 2;
231     while(nY <= nBottom)
232     {
233         aRenderState.AffineTransform.m12 = nY;
234         rxCanvas->drawBitmap(rxRepeatableCenterBitmap, aViewState, aRenderState);
235         nY += aCenterBitmapSize.Height;
236     }
237 }
238 
239 } } // end of namespace sdext::presenter
240 
241 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
242