1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_svx.hxx" 24 #include <svx/sdr/contact/viewcontactofgraphic.hxx> 25 #include <svx/sdr/contact/viewobjectcontactofgraphic.hxx> 26 #include <svx/svdograf.hxx> 27 #include <svx/sdr/primitive2d/sdrattributecreator.hxx> 28 #include <svl/itemset.hxx> 29 30 #ifndef ITEMID_GRF_CROP 31 #define ITEMID_GRF_CROP 0 32 #endif 33 34 #include <svx/sdgcpitm.hxx> 35 #include <svx/sdr/contact/displayinfo.hxx> 36 #include <svx/sdr/contact/viewobjectcontact.hxx> 37 #include <svx/sdr/contact/objectcontact.hxx> 38 #include <svx/sdr/event/eventhandler.hxx> 39 #include <basegfx/matrix/b2dhommatrix.hxx> 40 #include <svx/sdr/primitive2d/sdrgrafprimitive2d.hxx> 41 #include "svx/svdstr.hrc" 42 #include <svx/svdglob.hxx> 43 #include <vcl/svapp.hxx> 44 #include <basegfx/polygon/b2dpolygontools.hxx> 45 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> 46 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> 47 #include <drawinglayer/primitive2d/textprimitive2d.hxx> 48 #include <drawinglayer/primitive2d/textlayoutdevice.hxx> 49 #include <drawinglayer/primitive2d/maskprimitive2d.hxx> 50 #include <svx/sdr/primitive2d/sdrtextprimitive2d.hxx> 51 #include <editeng/eeitem.hxx> 52 #include <editeng/colritem.hxx> 53 #include <basegfx/matrix/b2dhommatrixtools.hxx> 54 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx> 55 56 namespace sdr 57 { 58 namespace contact 59 { 60 // Create a Object-Specific ViewObjectContact, set ViewContact and 61 // ObjectContact. Always needs to return something. 62 ViewObjectContact& ViewContactOfGraphic::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) 63 { 64 ViewObjectContact* pRetval = new ViewObjectContactOfGraphic(rObjectContact, *this); 65 DBG_ASSERT(pRetval, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)"); 66 67 return *pRetval; 68 } 69 70 ViewContactOfGraphic::ViewContactOfGraphic(SdrGrafObj& rGrafObj) 71 : ViewContactOfTextObj(rGrafObj) 72 { 73 } 74 75 ViewContactOfGraphic::~ViewContactOfGraphic() 76 { 77 } 78 79 void ViewContactOfGraphic::flushGraphicObjects() 80 { 81 // #i102380# The graphic is swapped out. To let that have an effect it is necessary to 82 // delete copies of the GraphicObject which are not swapped out and have no SwapHandler set 83 // (this is what happens when the GraphicObject gets copied to a SdrGrafPrimitive2D). This 84 // is best achieved for the VC by clearing the local decomposition cache. It would be possible 85 // to also do this for the VOC cache, but that VOCs exist exactly express that the object 86 // gets visualized, so this would be wrong. 87 flushViewIndependentPrimitive2DSequence(); 88 } 89 90 drawinglayer::primitive2d::Primitive2DSequence ViewContactOfGraphic::createVIP2DSForPresObj( 91 const basegfx::B2DHomMatrix& rObjectMatrix, 92 const drawinglayer::attribute::SdrLineFillShadowTextAttribute& rAttribute) const 93 { 94 drawinglayer::primitive2d::Primitive2DSequence xRetval; 95 GraphicObject aEmptyGraphicObject; 96 GraphicAttr aEmptyGraphicAttr; 97 98 // SdrGrafPrimitive2D without content in original size which carries all eventual attributes and texts 99 const drawinglayer::primitive2d::Primitive2DReference xReferenceA(new drawinglayer::primitive2d::SdrGrafPrimitive2D( 100 rObjectMatrix, 101 rAttribute, 102 aEmptyGraphicObject, 103 aEmptyGraphicAttr)); 104 xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReferenceA, 1); 105 106 // SdrGrafPrimitive2D with content (which is the preview graphic) scaled to smaller size and 107 // without attributes 108 basegfx::B2DHomMatrix aSmallerMatrix; 109 110 // #i94431# for some reason, i forgot to take the PrefMapMode of the graphic 111 // into account. Since EmptyPresObj's are only used in Draw/Impress, it is 112 // safe to assume 100th mm as target. 113 Size aPrefSize(GetGrafObject().GetGrafPrefSize()); 114 115 if(MAP_PIXEL == GetGrafObject().GetGrafPrefMapMode().GetMapUnit()) 116 { 117 aPrefSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MAP_100TH_MM); 118 } 119 else 120 { 121 aPrefSize = Application::GetDefaultDevice()->LogicToLogic(aPrefSize, GetGrafObject().GetGrafPrefMapMode(), MAP_100TH_MM); 122 } 123 124 // decompose object matrix to get single values 125 basegfx::B2DVector aScale, aTranslate; 126 double fRotate, fShearX; 127 rObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX); 128 129 const double fOffsetX((aScale.getX() - aPrefSize.getWidth()) / 2.0); 130 const double fOffsetY((aScale.getY() - aPrefSize.getHeight()) / 2.0); 131 132 if(basegfx::fTools::moreOrEqual(fOffsetX, 0.0) && basegfx::fTools::moreOrEqual(fOffsetY, 0.0)) 133 { 134 // create the EmptyPresObj fallback visualization. The fallback graphic 135 // is already provided in rGraphicObject in this case, use it 136 aSmallerMatrix = basegfx::tools::createScaleTranslateB2DHomMatrix(aPrefSize.getWidth(), aPrefSize.getHeight(), fOffsetX, fOffsetY); 137 aSmallerMatrix = basegfx::tools::createShearXRotateTranslateB2DHomMatrix(fShearX, fRotate, aTranslate) 138 * aSmallerMatrix; 139 140 const GraphicObject& rGraphicObject = GetGrafObject().GetGraphicObject(false); 141 const GraphicAttr aLocalGrafInfo; 142 const drawinglayer::primitive2d::Primitive2DReference xReferenceB(new drawinglayer::primitive2d::SdrGrafPrimitive2D( 143 aSmallerMatrix, 144 drawinglayer::attribute::SdrLineFillShadowTextAttribute(), 145 rGraphicObject, 146 aLocalGrafInfo)); 147 148 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, xReferenceB); 149 } 150 151 return xRetval; 152 } 153 154 drawinglayer::primitive2d::Primitive2DSequence ViewContactOfGraphic::createVIP2DSForDraft( 155 const basegfx::B2DHomMatrix& rObjectMatrix, 156 const drawinglayer::attribute::SdrLineFillShadowTextAttribute& rAttribute) const 157 { 158 drawinglayer::primitive2d::Primitive2DSequence xRetval; 159 GraphicObject aEmptyGraphicObject; 160 GraphicAttr aEmptyGraphicAttr; 161 162 // SdrGrafPrimitive2D without content in original size which carries all eventual attributes and texts 163 const drawinglayer::primitive2d::Primitive2DReference xReferenceA(new drawinglayer::primitive2d::SdrGrafPrimitive2D( 164 rObjectMatrix, 165 rAttribute, 166 aEmptyGraphicObject, 167 aEmptyGraphicAttr)); 168 xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReferenceA, 1); 169 170 if(rAttribute.getLine().isDefault()) 171 { 172 // create a surrounding frame when no linestyle given 173 const Color aColor(Application::GetSettings().GetStyleSettings().GetShadowColor()); 174 const basegfx::BColor aBColor(aColor.getBColor()); 175 basegfx::B2DPolygon aOutline(basegfx::tools::createUnitPolygon()); 176 aOutline.transform(rObjectMatrix); 177 178 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, 179 drawinglayer::primitive2d::Primitive2DReference( 180 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( 181 aOutline, 182 aBColor))); 183 } 184 185 // decompose object matrix to get single values 186 basegfx::B2DVector aScale, aTranslate; 187 double fRotate, fShearX; 188 rObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX); 189 190 // define a distance value, used for distance from bitmap to borders and from bitmap 191 // to text, too (2 mm) 192 const double fDistance(200.0); 193 194 // consume borders from values 195 aScale.setX(std::max(0.0, aScale.getX() - (2.0 * fDistance))); 196 aScale.setY(std::max(0.0, aScale.getY() - (2.0 * fDistance))); 197 aTranslate.setX(aTranslate.getX() + fDistance); 198 aTranslate.setY(aTranslate.getY() + fDistance); 199 200 // draw a draft bitmap 201 const Bitmap aDraftBitmap(ResId(BMAP_GrafikEi, *ImpGetResMgr())); 202 203 if(!aDraftBitmap.IsEmpty()) 204 { 205 Size aPrefSize(aDraftBitmap.GetPrefSize()); 206 207 if(MAP_PIXEL == aDraftBitmap.GetPrefMapMode().GetMapUnit()) 208 { 209 aPrefSize = Application::GetDefaultDevice()->PixelToLogic(aDraftBitmap.GetSizePixel(), MAP_100TH_MM); 210 } 211 else 212 { 213 aPrefSize = Application::GetDefaultDevice()->LogicToLogic(aPrefSize, aDraftBitmap.GetPrefMapMode(), MAP_100TH_MM); 214 } 215 216 const double fBitmapScaling(2.0); 217 const double fWidth(aPrefSize.getWidth() * fBitmapScaling); 218 const double fHeight(aPrefSize.getHeight() * fBitmapScaling); 219 220 if(basegfx::fTools::more(fWidth, 1.0) 221 && basegfx::fTools::more(fHeight, 1.0) 222 && basegfx::fTools::lessOrEqual(fWidth, aScale.getX()) 223 && basegfx::fTools::lessOrEqual(fHeight, aScale.getY())) 224 { 225 const basegfx::B2DHomMatrix aBitmapMatrix(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix( 226 fWidth, fHeight, fShearX, fRotate, aTranslate.getX(), aTranslate.getY())); 227 228 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, 229 drawinglayer::primitive2d::Primitive2DReference( 230 new drawinglayer::primitive2d::BitmapPrimitive2D( 231 BitmapEx(aDraftBitmap), 232 aBitmapMatrix))); 233 234 // consume bitmap size in X 235 aScale.setX(std::max(0.0, aScale.getX() - (fWidth + fDistance))); 236 aTranslate.setX(aTranslate.getX() + fWidth + fDistance); 237 } 238 } 239 240 // Build the text for the draft object 241 XubString aDraftText = GetGrafObject().GetFileName(); 242 243 if(!aDraftText.Len()) 244 { 245 aDraftText = GetGrafObject().GetName(); 246 aDraftText.AppendAscii(" ..."); 247 } 248 249 if(aDraftText.Len() && GetGrafObject().GetModel()) 250 { 251 // #i103255# Goal is to produce TextPrimitives which hold the given text as 252 // BlockText in the available space. It would be very tricky to do 253 // an own word wrap/line layout here. 254 // Using SdrBlockTextPrimitive2D OTOH is critical since it internally 255 // uses the SdrObject it references. To solve this, create a temp 256 // SdrObject with Attributes and Text, generate a SdrBlockTextPrimitive2D 257 // directly and immediately decompose it. After that, it is no longer 258 // needed and can be deleted. 259 260 // create temp RectObj as TextObj and set needed attributes 261 SdrRectObj aRectObj(OBJ_TEXT); 262 aRectObj.SetModel(GetGrafObject().GetModel()); 263 aRectObj.NbcSetText(aDraftText); 264 aRectObj.SetMergedItem(SvxColorItem(Color(COL_LIGHTRED), EE_CHAR_COLOR)); 265 266 // get SdrText and OPO 267 SdrText* pSdrText = aRectObj.getText(0); 268 OutlinerParaObject* pOPO = aRectObj.GetOutlinerParaObject(); 269 270 if(pSdrText && pOPO) 271 { 272 // directly use the remaining space as TextRangeTransform 273 const basegfx::B2DHomMatrix aTextRangeTransform(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix( 274 aScale, fShearX, fRotate, aTranslate)); 275 276 // directly create temp SdrBlockTextPrimitive2D 277 drawinglayer::primitive2d::SdrBlockTextPrimitive2D aBlockTextPrimitive( 278 pSdrText, 279 *pOPO, 280 aTextRangeTransform, 281 SDRTEXTHORZADJUST_LEFT, 282 SDRTEXTVERTADJUST_TOP, 283 false, 284 false, 285 false, 286 false, 287 false); 288 289 // decompose immediately with neutral ViewInformation. This will 290 // layout the text to more simple TextPrimitives from drawinglayer 291 const drawinglayer::geometry::ViewInformation2D aViewInformation2D; 292 293 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence( 294 xRetval, 295 aBlockTextPrimitive.get2DDecomposition(aViewInformation2D)); 296 } 297 } 298 299 return xRetval; 300 } 301 302 drawinglayer::primitive2d::Primitive2DSequence ViewContactOfGraphic::createViewIndependentPrimitive2DSequence() const 303 { 304 drawinglayer::primitive2d::Primitive2DSequence xRetval; 305 const SfxItemSet& rItemSet = GetGrafObject().GetMergedItemSet(); 306 307 // create and fill GraphicAttr 308 GraphicAttr aLocalGrafInfo; 309 const sal_uInt16 nTrans(((SdrGrafTransparenceItem&)rItemSet.Get(SDRATTR_GRAFTRANSPARENCE)).GetValue()); 310 const SdrGrafCropItem& rCrop((const SdrGrafCropItem&)rItemSet.Get(SDRATTR_GRAFCROP)); 311 aLocalGrafInfo.SetLuminance(((SdrGrafLuminanceItem&)rItemSet.Get(SDRATTR_GRAFLUMINANCE)).GetValue()); 312 aLocalGrafInfo.SetContrast(((SdrGrafContrastItem&)rItemSet.Get(SDRATTR_GRAFCONTRAST)).GetValue()); 313 aLocalGrafInfo.SetChannelR(((SdrGrafRedItem&)rItemSet.Get(SDRATTR_GRAFRED)).GetValue()); 314 aLocalGrafInfo.SetChannelG(((SdrGrafGreenItem&)rItemSet.Get(SDRATTR_GRAFGREEN)).GetValue()); 315 aLocalGrafInfo.SetChannelB(((SdrGrafBlueItem&)rItemSet.Get(SDRATTR_GRAFBLUE)).GetValue()); 316 aLocalGrafInfo.SetGamma(((SdrGrafGamma100Item&)rItemSet.Get(SDRATTR_GRAFGAMMA)).GetValue() * 0.01); 317 aLocalGrafInfo.SetTransparency((sal_uInt8)::basegfx::fround(Min(nTrans, (sal_uInt16)100) * 2.55)); 318 aLocalGrafInfo.SetInvert(((SdrGrafInvertItem&)rItemSet.Get(SDRATTR_GRAFINVERT)).GetValue()); 319 aLocalGrafInfo.SetDrawMode(((SdrGrafModeItem&)rItemSet.Get(SDRATTR_GRAFMODE)).GetValue()); 320 aLocalGrafInfo.SetCrop(rCrop.GetLeft(), rCrop.GetTop(), rCrop.GetRight(), rCrop.GetBottom()); 321 322 // we have content if graphic is not completely transparent 323 const bool bHasContent(255L != aLocalGrafInfo.GetTransparency()); 324 drawinglayer::attribute::SdrLineFillShadowTextAttribute aAttribute( 325 drawinglayer::primitive2d::createNewSdrLineFillShadowTextAttribute( 326 rItemSet, 327 GetGrafObject().getText(0), 328 bHasContent)); 329 330 // take unrotated snap rect for position and size. Directly use model data, not getBoundRect() or getSnapRect() 331 // which will use the primitive data we just create in the near future 332 const Rectangle& rRectangle = GetGrafObject().GetGeoRect(); 333 const ::basegfx::B2DRange aObjectRange( 334 rRectangle.Left(), rRectangle.Top(), 335 rRectangle.Right(), rRectangle.Bottom()); 336 337 // look for mirroring 338 const GeoStat& rGeoStat(GetGrafObject().GetGeoStat()); 339 const sal_Int32 nDrehWink(rGeoStat.nDrehWink); 340 const bool bRota180(18000 == nDrehWink); 341 const bool bMirrored(GetGrafObject().IsMirrored()); 342 const sal_uInt16 nMirrorCase(bRota180 ? (bMirrored ? 3 : 4) : (bMirrored ? 2 : 1)); 343 bool bHMirr((2 == nMirrorCase ) || (4 == nMirrorCase)); 344 bool bVMirr((3 == nMirrorCase ) || (4 == nMirrorCase)); 345 346 // set mirror flags at LocalGrafInfo. Take into account that the geometry in 347 // aObjectRange is already changed and rotated when bRota180 is used. To rebuild 348 // that old behavior (as long as part of the model data), correct the H/V flags 349 // accordingly. The created bitmapPrimitive WILL use the rotation, too. 350 if(bRota180) 351 { 352 // if bRota180 which is used for vertical mirroring, the graphic will already be rotated 353 // by 180 degrees. To correct, switch off VMirror and invert HMirroring. 354 bHMirr = !bHMirr; 355 bVMirr = false; 356 } 357 358 if(bHMirr || bVMirr) 359 { 360 aLocalGrafInfo.SetMirrorFlags((bHMirr ? BMP_MIRROR_HORZ : 0)|(bVMirr ? BMP_MIRROR_VERT : 0)); 361 } 362 363 // fill object matrix 364 const double fShearX(rGeoStat.nShearWink ? tan((36000 - rGeoStat.nShearWink) * F_PI18000) : 0.0); 365 const double fRotate(nDrehWink ? (36000 - nDrehWink) * F_PI18000 : 0.0); 366 const basegfx::B2DHomMatrix aObjectMatrix(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix( 367 aObjectRange.getWidth(), aObjectRange.getHeight(), 368 fShearX, fRotate, 369 aObjectRange.getMinX(), aObjectRange.getMinY())); 370 371 // get the current, unchanged graphic object from SdrGrafObj 372 const GraphicObject& rGraphicObject = GetGrafObject().GetGraphicObject(false); 373 374 if(visualisationUsesPresObj()) 375 { 376 // it's an EmptyPresObj, create the SdrGrafPrimitive2D without content and another scaled one 377 // with the content which is the placeholder graphic 378 xRetval = createVIP2DSForPresObj(aObjectMatrix, aAttribute); 379 } 380 else if(visualisationUsesDraft()) 381 { 382 // #i102380# The graphic is swapped out. To not force a swap-in here, there is a mechanism 383 // which shows a swapped-out-visualization (which gets created here now) and an asynchronous 384 // visual update mechanism for swapped-out graphics when they were loaded (see AsynchGraphicLoadingEvent 385 // and ViewObjectContactOfGraphic implementation). Not forcing the swap-in here allows faster 386 // (non-blocking) processing here and thus in the effect e.g. fast scrolling through pages 387 xRetval = createVIP2DSForDraft(aObjectMatrix, aAttribute); 388 } 389 else 390 { 391 // create primitive. Info: Calling the copy-constructor of GraphicObject in this 392 // SdrGrafPrimitive2D constructor will force a full swap-in of the graphic 393 const drawinglayer::primitive2d::Primitive2DReference xReference( 394 new drawinglayer::primitive2d::SdrGrafPrimitive2D( 395 aObjectMatrix, 396 aAttribute, 397 rGraphicObject, 398 aLocalGrafInfo)); 399 400 xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); 401 } 402 403 // always append an invisible outline for the cases where no visible content exists 404 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, 405 drawinglayer::primitive2d::createHiddenGeometryPrimitives2D( 406 false, aObjectMatrix)); 407 408 return xRetval; 409 } 410 411 bool ViewContactOfGraphic::visualisationUsesPresObj() const 412 { 413 return GetGrafObject().IsEmptyPresObj(); 414 } 415 416 bool ViewContactOfGraphic::visualisationUsesDraft() const 417 { 418 // no draft when already PresObj 419 if(visualisationUsesPresObj()) 420 return false; 421 422 // draft when swapped out 423 const GraphicObject& rGraphicObject = GetGrafObject().GetGraphicObject(false); 424 static bool bAllowReplacements(true); 425 426 if(rGraphicObject.IsSwappedOut() && bAllowReplacements) 427 return true; 428 429 // draft when no graphic 430 if(GRAPHIC_NONE == rGraphicObject.GetType() || GRAPHIC_DEFAULT == rGraphicObject.GetType()) 431 return true; 432 433 return false; 434 } 435 436 } // end of namespace contact 437 } // end of namespace sdr 438 439 /* vim: set noet sw=4 ts=4: */ 440