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