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 311 // create and fill GraphicAttr 312 GraphicAttr aLocalGrafInfo; 313 const sal_uInt16 nTrans(((SdrGrafTransparenceItem&)rItemSet.Get(SDRATTR_GRAFTRANSPARENCE)).GetValue()); 314 const SdrGrafCropItem& rCrop((const SdrGrafCropItem&)rItemSet.Get(SDRATTR_GRAFCROP)); 315 aLocalGrafInfo.SetLuminance(((SdrGrafLuminanceItem&)rItemSet.Get(SDRATTR_GRAFLUMINANCE)).GetValue()); 316 aLocalGrafInfo.SetContrast(((SdrGrafContrastItem&)rItemSet.Get(SDRATTR_GRAFCONTRAST)).GetValue()); 317 aLocalGrafInfo.SetChannelR(((SdrGrafRedItem&)rItemSet.Get(SDRATTR_GRAFRED)).GetValue()); 318 aLocalGrafInfo.SetChannelG(((SdrGrafGreenItem&)rItemSet.Get(SDRATTR_GRAFGREEN)).GetValue()); 319 aLocalGrafInfo.SetChannelB(((SdrGrafBlueItem&)rItemSet.Get(SDRATTR_GRAFBLUE)).GetValue()); 320 aLocalGrafInfo.SetGamma(((SdrGrafGamma100Item&)rItemSet.Get(SDRATTR_GRAFGAMMA)).GetValue() * 0.01); 321 aLocalGrafInfo.SetTransparency((sal_uInt8)::basegfx::fround(Min(nTrans, (sal_uInt16)100) * 2.55)); 322 aLocalGrafInfo.SetInvert(((SdrGrafInvertItem&)rItemSet.Get(SDRATTR_GRAFINVERT)).GetValue()); 323 aLocalGrafInfo.SetDrawMode(((SdrGrafModeItem&)rItemSet.Get(SDRATTR_GRAFMODE)).GetValue()); 324 aLocalGrafInfo.SetCrop(rCrop.GetLeft(), rCrop.GetTop(), rCrop.GetRight(), rCrop.GetBottom()); 325 326 // we have content if graphic is not completely transparent 327 const bool bHasContent(255L != aLocalGrafInfo.GetTransparency()); 328 drawinglayer::attribute::SdrLineFillShadowTextAttribute aAttribute( 329 drawinglayer::primitive2d::createNewSdrLineFillShadowTextAttribute( 330 rItemSet, 331 GetGrafObject().getText(0), 332 bHasContent)); 333 334 // take unrotated snap rect for position and size. Directly use model data, not getBoundRect() or getSnapRect() 335 // which will use the primitive data we just create in the near future 336 const Rectangle& rRectangle = GetGrafObject().GetGeoRect(); 337 const ::basegfx::B2DRange aObjectRange( 338 rRectangle.Left(), rRectangle.Top(), 339 rRectangle.Right(), rRectangle.Bottom()); 340 341 // look for mirroring 342 const GeoStat& rGeoStat(GetGrafObject().GetGeoStat()); 343 const sal_Int32 nDrehWink(rGeoStat.nDrehWink); 344 const bool bRota180(18000 == nDrehWink); 345 const bool bMirrored(GetGrafObject().IsMirrored()); 346 const sal_uInt16 nMirrorCase(bRota180 ? (bMirrored ? 3 : 4) : (bMirrored ? 2 : 1)); 347 bool bHMirr((2 == nMirrorCase ) || (4 == nMirrorCase)); 348 bool bVMirr((3 == nMirrorCase ) || (4 == nMirrorCase)); 349 350 // set mirror flags at LocalGrafInfo. Take into account that the geometry in 351 // aObjectRange is already changed and rotated when bRota180 is used. To rebuild 352 // that old behaviour (as long as part of the model data), correct the H/V flags 353 // accordingly. The created bitmapPrimitive WILL use the rotation, too. 354 if(bRota180) 355 { 356 // if bRota180 which is used for vertical mirroring, the graphic will already be rotated 357 // by 180 degrees. To correct, switch off VMirror and invert HMirroring. 358 bHMirr = !bHMirr; 359 bVMirr = false; 360 } 361 362 if(bHMirr || bVMirr) 363 { 364 aLocalGrafInfo.SetMirrorFlags((bHMirr ? BMP_MIRROR_HORZ : 0)|(bVMirr ? BMP_MIRROR_VERT : 0)); 365 } 366 367 // fill object matrix 368 const double fShearX(rGeoStat.nShearWink ? tan((36000 - rGeoStat.nShearWink) * F_PI18000) : 0.0); 369 const double fRotate(nDrehWink ? (36000 - nDrehWink) * F_PI18000 : 0.0); 370 const basegfx::B2DHomMatrix aObjectMatrix(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix( 371 aObjectRange.getWidth(), aObjectRange.getHeight(), 372 fShearX, fRotate, 373 aObjectRange.getMinX(), aObjectRange.getMinY())); 374 375 // get the current, unchenged graphic obect from SdrGrafObj 376 const GraphicObject& rGraphicObject = GetGrafObject().GetGraphicObject(false); 377 378 if(visualisationUsesPresObj()) 379 { 380 // it's an EmptyPresObj, create the SdrGrafPrimitive2D without content and another scaled one 381 // with the content which is the placeholder graphic 382 xRetval = createVIP2DSForPresObj(aObjectMatrix, aAttribute, aLocalGrafInfo); 383 } 384 else if(visualisationUsesDraft()) 385 { 386 // #i102380# The graphic is swapped out. To not force a swap-in here, there is a mechanism 387 // which shows a swapped-out-visualisation (which gets created here now) and an asynchronious 388 // visual update mechanism for swapped-out grapgics when they were loaded (see AsynchGraphicLoadingEvent 389 // and ViewObjectContactOfGraphic implementation). Not forcing the swap-in here allows faster 390 // (non-blocking) processing here and thus in the effect e.g. fast scrolling through pages 391 xRetval = createVIP2DSForDraft(aObjectMatrix, aAttribute); 392 } 393 else 394 { 395 // create primitive. Info: Calling the copy-constructor of GraphicObject in this 396 // SdrGrafPrimitive2D constructor will force a full swap-in of the graphic 397 const drawinglayer::primitive2d::Primitive2DReference xReference( 398 new drawinglayer::primitive2d::SdrGrafPrimitive2D( 399 aObjectMatrix, 400 aAttribute, 401 rGraphicObject, 402 aLocalGrafInfo)); 403 404 xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); 405 } 406 407 // always append an invisible outline for the cases where no visible content exists 408 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, 409 drawinglayer::primitive2d::createHiddenGeometryPrimitives2D( 410 false, aObjectMatrix)); 411 412 return xRetval; 413 } 414 415 bool ViewContactOfGraphic::visualisationUsesPresObj() const 416 { 417 return GetGrafObject().IsEmptyPresObj(); 418 } 419 420 bool ViewContactOfGraphic::visualisationUsesDraft() const 421 { 422 // no draft when already PresObj 423 if(visualisationUsesPresObj()) 424 return false; 425 426 // draft when swapped out 427 const GraphicObject& rGraphicObject = GetGrafObject().GetGraphicObject(false); 428 static bool bAllowReplacements(true); 429 430 if(rGraphicObject.IsSwappedOut() && bAllowReplacements) 431 return true; 432 433 // draft when no graphic 434 if(GRAPHIC_NONE == rGraphicObject.GetType() || GRAPHIC_DEFAULT == rGraphicObject.GetType()) 435 return true; 436 437 return false; 438 } 439 440 } // end of namespace contact 441 } // end of namespace sdr 442 443 ////////////////////////////////////////////////////////////////////////////// 444 // eof 445