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