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