Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
30 : : #include <com/sun/star/beans/XPropertySet.hpp>
31 : : #include <comphelper/processfactory.hxx>
32 : : #include <com/sun/star/awt/XWindow2.hpp>
33 : : #include <drawinglayer/geometry/viewinformation2d.hxx>
34 : : #include <vcl/virdev.hxx>
35 : : #include <vcl/svapp.hxx>
36 : : #include <com/sun/star/awt/PosSize.hpp>
37 : : #include <vcl/bitmapex.hxx>
38 : : #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
39 : : #include <tools/diagnose_ex.h>
40 : : #include <basegfx/polygon/b2dpolygontools.hxx>
41 : : #include <basegfx/polygon/b2dpolygon.hxx>
42 : : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
43 : : #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
44 : : #include <svtools/optionsdrawinglayer.hxx>
45 : : #include <toolkit/awt/vclxwindow.hxx>
46 : : #include <vcl/window.hxx>
47 : : #include <basegfx/matrix/b2dhommatrixtools.hxx>
48 : :
49 : : //////////////////////////////////////////////////////////////////////////////
50 : :
51 : : using namespace com::sun::star;
52 : :
53 : : //////////////////////////////////////////////////////////////////////////////
54 : :
55 : : namespace drawinglayer
56 : : {
57 : : namespace primitive2d
58 : : {
59 : 3051 : void ControlPrimitive2D::createXControl()
60 : : {
61 [ + - ][ + - ]: 3051 : if(!mxXControl.is() && getControlModel().is())
[ + - ]
62 : : {
63 [ + - ]: 3051 : uno::Reference< beans::XPropertySet > xSet(getControlModel(), uno::UNO_QUERY);
64 : :
65 [ + - ]: 3051 : if(xSet.is())
66 : : {
67 [ + - ][ + - ]: 3051 : uno::Any aValue(xSet->getPropertyValue("DefaultControl"));
68 : 3051 : rtl::OUString aUnoControlTypeName;
69 : :
70 [ + - ]: 3051 : if(aValue >>= aUnoControlTypeName)
71 : : {
72 [ + - ]: 3051 : if(!aUnoControlTypeName.isEmpty())
73 : : {
74 [ + - ]: 3051 : uno::Reference< lang::XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
75 : :
76 [ + - ]: 3051 : if(xFactory.is())
77 : : {
78 [ + - ][ + - ]: 3051 : uno::Reference< awt::XControl > xXControl(xFactory->createInstance(aUnoControlTypeName), uno::UNO_QUERY);
[ + - ]
79 : :
80 [ + + ]: 3051 : if(xXControl.is())
81 : : {
82 [ + - ][ + - ]: 33 : xXControl->setModel(getControlModel());
83 : :
84 : : // remember XControl
85 [ + - ]: 33 : mxXControl = xXControl;
86 : 3051 : }
87 : 3051 : }
88 : : }
89 : 3051 : }
90 : 3051 : }
91 : : }
92 : 3051 : }
93 : :
94 : 150 : Primitive2DReference ControlPrimitive2D::createBitmapDecomposition(const geometry::ViewInformation2D& rViewInformation) const
95 : : {
96 : 150 : Primitive2DReference xRetval;
97 [ + - ]: 150 : const uno::Reference< awt::XControl >& rXControl(getXControl());
98 : :
99 [ + + ]: 150 : if(rXControl.is())
100 : : {
101 [ + - ]: 2 : uno::Reference< awt::XWindow > xControlWindow(rXControl, uno::UNO_QUERY);
102 : :
103 [ + - ]: 2 : if(xControlWindow.is())
104 : : {
105 : : // get decomposition to get size
106 : 2 : basegfx::B2DVector aScale, aTranslate;
107 : : double fRotate, fShearX;
108 [ + - ]: 2 : getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
109 : :
110 : : // get absolute discrete size (no mirror or rotate here)
111 [ + - ]: 2 : aScale = basegfx::absolute(aScale);
112 [ + - ][ + - ]: 2 : basegfx::B2DVector aDiscreteSize(rViewInformation.getObjectToViewTransformation() * aScale);
113 : :
114 : : // limit to a maximum square size, e.g. 300x150 pixels (45000)
115 [ + - ]: 2 : const SvtOptionsDrawinglayer aDrawinglayerOpt;
116 [ + - ]: 2 : const double fDiscreteMax(aDrawinglayerOpt.GetQuadraticFormControlRenderLimit());
117 : 2 : const double fDiscreteQuadratic(aDiscreteSize.getX() * aDiscreteSize.getY());
118 : 2 : const bool bScaleUsed(fDiscreteQuadratic > fDiscreteMax);
119 : 2 : double fFactor(1.0);
120 : :
121 [ + - ]: 2 : if(bScaleUsed)
122 : : {
123 : : // get factor and adapt to scaled size
124 : 2 : fFactor = sqrt(fDiscreteMax / fDiscreteQuadratic);
125 : 2 : aDiscreteSize *= fFactor;
126 : : }
127 : :
128 : : // go to integer
129 : 2 : const sal_Int32 nSizeX(basegfx::fround(aDiscreteSize.getX()));
130 : 2 : const sal_Int32 nSizeY(basegfx::fround(aDiscreteSize.getY()));
131 : :
132 [ + - ][ + - ]: 2 : if(nSizeX > 0 && nSizeY > 0)
133 : : {
134 : : // prepare VirtualDevice
135 [ + - ][ + - ]: 2 : VirtualDevice aVirtualDevice(*Application::GetDefaultDevice());
136 : 2 : const Size aSizePixel(nSizeX, nSizeY);
137 [ + - ]: 2 : aVirtualDevice.SetOutputSizePixel(aSizePixel);
138 : :
139 : : // set size at control
140 [ + - ][ + - ]: 2 : xControlWindow->setPosSize(0, 0, nSizeX, nSizeY, awt::PosSize::POSSIZE);
141 : :
142 : : // get graphics and view
143 [ + - ]: 2 : uno::Reference< awt::XGraphics > xGraphics(aVirtualDevice.CreateUnoGraphics());
144 [ + - ]: 2 : uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY);
145 : :
146 [ + - ][ + - ]: 2 : if(xGraphics.is() && xControlView.is())
[ + - ]
147 : : {
148 : : // link graphics and view
149 [ + - ][ + - ]: 2 : xControlView->setGraphics(xGraphics);
150 : :
151 : : { // #i93162# For painting the control setting a Zoom (using setZoom() at the xControlView)
152 : : // is needed to define the font size. Normally this is done in
153 : : // ViewObjectContactOfUnoControl::createPrimitive2DSequence by using positionControlForPaint().
154 : : // For some reason the difference between MAP_TWIPS and MAP_100TH_MM still plays
155 : : // a role there so that for Draw/Impress/Calc (the MAP_100TH_MM users) i need to set a zoom
156 : : // here, too. The factor includes the needed scale, but is calculated by pure comparisons. It
157 : : // is somehow related to the twips/100thmm relationship.
158 : 2 : bool bUserIs100thmm(false);
159 [ + - ]: 2 : const uno::Reference< awt::XControl > xControl(xControlView, uno::UNO_QUERY);
160 : :
161 [ + - ]: 2 : if(xControl.is())
162 : : {
163 [ + - ][ + - ]: 2 : uno::Reference< awt::XWindowPeer > xWindowPeer(xControl->getPeer());
164 : :
165 [ - + ]: 2 : if(xWindowPeer.is())
166 : : {
167 : 0 : VCLXWindow* pVCLXWindow = VCLXWindow::GetImplementation(xWindowPeer);
168 : :
169 [ # # ]: 0 : if(pVCLXWindow)
170 : : {
171 : 0 : Window* pWindow = pVCLXWindow->GetWindow();
172 : :
173 [ # # ]: 0 : if(pWindow)
174 : : {
175 [ # # ]: 0 : pWindow = pWindow->GetParent();
176 : :
177 [ # # ]: 0 : if(pWindow)
178 : : {
179 [ # # ]: 0 : if(MAP_100TH_MM == pWindow->GetMapMode().GetMapUnit())
180 : : {
181 : 0 : bUserIs100thmm = true;
182 : : }
183 : : }
184 : : }
185 : : }
186 : 2 : }
187 : : }
188 : :
189 [ - + ]: 2 : if(bUserIs100thmm)
190 : : {
191 : : // calc screen zoom for text display. fFactor is already added indirectly in aDiscreteSize
192 : : basegfx::B2DVector aScreenZoom(
193 : 0 : basegfx::fTools::equalZero(aScale.getX()) ? 1.0 : aDiscreteSize.getX() / aScale.getX(),
194 [ # # ][ # # ]: 0 : basegfx::fTools::equalZero(aScale.getY()) ? 1.0 : aDiscreteSize.getY() / aScale.getY());
195 : : static double fZoomScale(28.0); // do not ask for this constant factor, but it gets the zoom right
196 : 0 : aScreenZoom *= fZoomScale;
197 : :
198 : : // set zoom at control view for text scaling
199 [ # # ][ # # ]: 0 : xControlView->setZoom((float)aScreenZoom.getX(), (float)aScreenZoom.getY());
200 : 2 : }
201 : : }
202 : :
203 : : try
204 : : {
205 : : // try to paint it to VirtualDevice
206 [ + - ][ + - ]: 2 : xControlView->draw(0, 0);
207 : :
208 : : // get bitmap
209 [ + - ]: 2 : const Bitmap aContent(aVirtualDevice.GetBitmap(Point(), aSizePixel));
210 : :
211 : : // to avoid scaling, use the Bitmap pixel size as primitive size
212 [ + - ]: 2 : const Size aBitmapSize(aContent.GetSizePixel());
213 : : basegfx::B2DVector aBitmapSizeLogic(
214 [ + - ]: 2 : rViewInformation.getInverseObjectToViewTransformation() *
215 [ + - ]: 4 : basegfx::B2DVector(aBitmapSize.getWidth() - 1, aBitmapSize.getHeight() - 1));
216 : :
217 [ + - ]: 2 : if(bScaleUsed)
218 : : {
219 : : // if scaled adapt to scaled size
220 : 2 : aBitmapSizeLogic /= fFactor;
221 : : }
222 : :
223 : : // short form for scale and translate transformation
224 : : const basegfx::B2DHomMatrix aBitmapTransform(basegfx::tools::createScaleTranslateB2DHomMatrix(
225 [ + - ]: 2 : aBitmapSizeLogic.getX(), aBitmapSizeLogic.getY(), aTranslate.getX(), aTranslate.getY()));
226 : :
227 : : // create primitive
228 [ + - ][ + - ]: 2 : xRetval = new BitmapPrimitive2D(BitmapEx(aContent), aBitmapTransform);
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ # # ]
229 : : }
230 [ # # ]: 0 : catch( const uno::Exception& )
231 : : {
232 : : DBG_UNHANDLED_EXCEPTION();
233 : : }
234 [ + - ]: 2 : }
235 [ + - ]: 2 : }
236 : 2 : }
237 : : }
238 : :
239 : 150 : return xRetval;
240 : : }
241 : :
242 : 148 : Primitive2DReference ControlPrimitive2D::createPlaceholderDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
243 : : {
244 : : // create a gray placeholder hairline polygon in object size
245 [ + - ]: 148 : basegfx::B2DRange aObjectRange(0.0, 0.0, 1.0, 1.0);
246 [ + - ]: 148 : aObjectRange.transform(getTransform());
247 [ + - ]: 148 : const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aObjectRange));
248 : 148 : const basegfx::BColor aGrayTone(0xc0 / 255.0, 0xc0 / 255.0, 0xc0 / 255.0);
249 : :
250 : : // The replacement object may also get a text like 'empty group' here later
251 [ + - ][ + - ]: 148 : Primitive2DReference xRetval(new PolygonHairlinePrimitive2D(aOutline, aGrayTone));
[ + - ]
252 : :
253 [ + - ]: 148 : return xRetval;
254 : : }
255 : :
256 : 150 : Primitive2DSequence ControlPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
257 : : {
258 : : // try to create a bitmap decomposition. If that fails for some reason,
259 : : // at least create a replacement decomposition.
260 [ + - ]: 150 : Primitive2DReference xReference(createBitmapDecomposition(rViewInformation));
261 : :
262 [ + + ]: 150 : if(!xReference.is())
263 : : {
264 [ + - ][ + - ]: 148 : xReference = createPlaceholderDecomposition(rViewInformation);
265 : : }
266 : :
267 [ + - ]: 150 : return Primitive2DSequence(&xReference, 1L);
268 : : }
269 : :
270 : 891 : ControlPrimitive2D::ControlPrimitive2D(
271 : : const basegfx::B2DHomMatrix& rTransform,
272 : : const uno::Reference< awt::XControlModel >& rxControlModel)
273 : : : BufferedDecompositionPrimitive2D(),
274 : : maTransform(rTransform),
275 : : mxControlModel(rxControlModel),
276 : : mxXControl(),
277 [ + - ]: 891 : maLastViewScaling()
278 : : {
279 : 891 : }
280 : :
281 : 3288 : ControlPrimitive2D::ControlPrimitive2D(
282 : : const basegfx::B2DHomMatrix& rTransform,
283 : : const uno::Reference< awt::XControlModel >& rxControlModel,
284 : : const uno::Reference< awt::XControl >& rxXControl)
285 : : : BufferedDecompositionPrimitive2D(),
286 : : maTransform(rTransform),
287 : : mxControlModel(rxControlModel),
288 : : mxXControl(rxXControl),
289 [ + - ]: 3288 : maLastViewScaling()
290 : : {
291 : 3288 : }
292 : :
293 : 7526 : const uno::Reference< awt::XControl >& ControlPrimitive2D::getXControl() const
294 : : {
295 [ + + ]: 7526 : if(!mxXControl.is())
296 : : {
297 : 3051 : const_cast< ControlPrimitive2D* >(this)->createXControl();
298 : : }
299 : :
300 : 7526 : return mxXControl;
301 : : }
302 : :
303 : 440 : bool ControlPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
304 : : {
305 : : // use base class compare operator
306 [ + + ]: 440 : if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
307 : : {
308 : 406 : const ControlPrimitive2D& rCompare = (ControlPrimitive2D&)rPrimitive;
309 : :
310 [ + + ]: 406 : if(getTransform() == rCompare.getTransform())
311 : : {
312 : : // check if ControlModel references both are/are not
313 : 186 : bool bRetval(getControlModel().is() == rCompare.getControlModel().is());
314 : :
315 [ + - ][ + - ]: 186 : if(bRetval && getControlModel().is())
[ + - ]
316 : : {
317 : : // both exist, check for equality
318 : 186 : bRetval = (getControlModel() == rCompare.getControlModel());
319 : : }
320 : :
321 [ + - ]: 186 : if(bRetval)
322 : : {
323 : : // check if XControl references both are/are not
324 : 186 : bRetval = (getXControl().is() == rCompare.getXControl().is());
325 : : }
326 : :
327 [ + - ][ + + ]: 186 : if(bRetval && getXControl().is())
[ + + ]
328 : : {
329 : : // both exist, check for equality
330 : 46 : bRetval = (getXControl() == rCompare.getXControl());
331 : : }
332 : :
333 : 186 : return bRetval;
334 : : }
335 : : }
336 : :
337 : 440 : return false;
338 : : }
339 : :
340 : 762 : basegfx::B2DRange ControlPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
341 : : {
342 : : // simply derivate from unit range
343 : 762 : basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
344 : 762 : aRetval.transform(getTransform());
345 : 762 : return aRetval;
346 : : }
347 : :
348 : 2452 : Primitive2DSequence ControlPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
349 : : {
350 : : // this primitive is view-dependent related to the scaling. If scaling has changed,
351 : : // destroy existing decomposition. To detect change, use size of unit size in view coordinates
352 [ + - ]: 2452 : ::osl::MutexGuard aGuard( m_aMutex );
353 [ + - ][ + - ]: 2452 : const basegfx::B2DVector aNewScaling(rViewInformation.getObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
354 : :
355 [ + + ]: 2452 : if(getBuffered2DDecomposition().hasElements())
356 : : {
357 [ - + ]: 2302 : if(!maLastViewScaling.equal(aNewScaling))
358 : : {
359 : : // conditions of last local decomposition have changed, delete
360 [ # # ][ # # ]: 0 : const_cast< ControlPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence());
[ # # ]
361 : : }
362 : : }
363 : :
364 [ + + ]: 2452 : if(!getBuffered2DDecomposition().hasElements())
365 : : {
366 : : // remember ViewTransformation
367 [ + - ]: 150 : const_cast< ControlPrimitive2D* >(this)->maLastViewScaling = aNewScaling;
368 : : }
369 : :
370 : : // use parent implementation
371 [ + - ][ + - ]: 2452 : return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
372 : : }
373 : :
374 : : // provide unique ID
375 : 7595 : ImplPrimitrive2DIDBlock(ControlPrimitive2D, PRIMITIVE2D_ID_CONTROLPRIMITIVE2D)
376 : :
377 : : } // end of namespace primitive2d
378 : : } // end of namespace drawinglayer
379 : :
380 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|