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/viewcontactofsdrobjcustomshape.hxx> 27 #include <svx/svdoashp.hxx> 28 #include <svx/sdr/contact/displayinfo.hxx> 29 #include <svx/sdr/primitive2d/sdrattributecreator.hxx> 30 #include <svx/svditer.hxx> 31 #include <svx/sdr/primitive2d/sdrcustomshapeprimitive2d.hxx> 32 #include <basegfx/polygon/b2dpolygontools.hxx> 33 #include <basegfx/polygon/b2dpolygon.hxx> 34 #include <basegfx/matrix/b2dhommatrixtools.hxx> 35 #include <svx/obj3d.hxx> 36 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx> 37 38 ////////////////////////////////////////////////////////////////////////////// 39 40 namespace sdr 41 { 42 namespace contact 43 { ViewContactOfSdrObjCustomShape(SdrObjCustomShape & rCustomShape)44 ViewContactOfSdrObjCustomShape::ViewContactOfSdrObjCustomShape(SdrObjCustomShape& rCustomShape) 45 : ViewContactOfTextObj(rCustomShape) 46 { 47 } 48 ~ViewContactOfSdrObjCustomShape()49 ViewContactOfSdrObjCustomShape::~ViewContactOfSdrObjCustomShape() 50 { 51 } 52 getCorrectedTextBoundRect() const53 basegfx::B2DRange ViewContactOfSdrObjCustomShape::getCorrectedTextBoundRect() const 54 { 55 const Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect()); 56 Rectangle aTextBound(aObjectBound); 57 GetCustomShapeObj().GetTextBounds(aTextBound); 58 basegfx::B2DRange aTextRange(aTextBound.Left(), aTextBound.Top(), aTextBound.Right(), aTextBound.Bottom()); 59 const basegfx::B2DRange aObjectRange(aObjectBound.Left(), aObjectBound.Top(), aObjectBound.Right(), aObjectBound.Bottom()); 60 61 // no need to correct if no extra text range 62 if(aTextRange != aObjectRange) 63 { 64 const GeoStat& rGeoStat(GetCustomShapeObj().GetGeoStat()); 65 66 // only correct when rotation and/or shear is used 67 if(rGeoStat.nShearWink || rGeoStat.nDrehWink ) 68 { 69 // text range needs to be corrected by 70 // aObjectRange.getCenter() - aRotObjectRange.getCenter() since it's 71 // defined differenly by using rotation around object center. Start 72 // with positive part 73 basegfx::B2DVector aTranslation(aObjectRange.getCenter()); 74 75 // get rotated and sheared object's range 76 basegfx::B2DRange aRotObjectRange(aObjectRange); 77 basegfx::B2DHomMatrix aRotMatrix; 78 79 aRotMatrix.translate(-aObjectRange.getMinimum().getX(), -aObjectRange.getMinimum().getY()); 80 81 if(rGeoStat.nShearWink) 82 { 83 aRotMatrix.shearX(tan((36000 - rGeoStat.nShearWink) * F_PI18000)); 84 } 85 86 if(rGeoStat.nDrehWink) 87 { 88 aRotMatrix.rotate((36000 - rGeoStat.nDrehWink) * F_PI18000); 89 } 90 91 aRotMatrix.translate(aObjectRange.getMinimum().getX(), aObjectRange.getMinimum().getY()); 92 aRotObjectRange.transform(aRotMatrix); 93 94 // add negative translation part 95 aTranslation -= aRotObjectRange.getCenter(); 96 97 // create new range 98 aTextRange = basegfx::B2DRange( 99 aTextRange.getMinX() + aTranslation.getX(), aTextRange.getMinY() + aTranslation.getY(), 100 aTextRange.getMaxX() + aTranslation.getX(), aTextRange.getMaxY() + aTranslation.getY()); 101 } 102 } 103 104 return aTextRange; 105 } 106 createViewIndependentPrimitive2DSequence() const107 drawinglayer::primitive2d::Primitive2DSequence ViewContactOfSdrObjCustomShape::createViewIndependentPrimitive2DSequence() const 108 { 109 drawinglayer::primitive2d::Primitive2DSequence xRetval; 110 const SfxItemSet& rItemSet = GetCustomShapeObj().GetMergedItemSet(); 111 112 // #i98072# Get shandow and text; eventually suppress the text if it's 113 // a TextPath FontworkGallery object 114 const drawinglayer::attribute::SdrShadowTextAttribute aAttribute( 115 drawinglayer::primitive2d::createNewSdrShadowTextAttribute( 116 rItemSet, 117 GetCustomShapeObj().getText(0), 118 GetCustomShapeObj().IsTextPath())); 119 drawinglayer::primitive2d::Primitive2DSequence xGroup; 120 bool bHasText(!aAttribute.getText().isDefault()); 121 122 // create Primitive2DSequence from sub-geometry 123 const SdrObject* pSdrObjRepresentation = GetCustomShapeObj().GetSdrObjectFromCustomShape(); 124 bool b3DShape(false); 125 126 if(pSdrObjRepresentation) 127 { 128 SdrObjListIter aIterator(*pSdrObjRepresentation); 129 130 while(aIterator.IsMore()) 131 { 132 SdrObject& rCandidate = *aIterator.Next(); 133 134 if(!b3DShape && dynamic_cast< E3dObject* >(&rCandidate)) 135 { 136 b3DShape = true; 137 } 138 139 const drawinglayer::primitive2d::Primitive2DSequence xNew(rCandidate.GetViewContact().getViewIndependentPrimitive2DSequence()); 140 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xGroup, xNew); 141 } 142 } 143 144 if(bHasText || xGroup.hasElements()) 145 { 146 // prepare text box geometry 147 basegfx::B2DHomMatrix aTextBoxMatrix; 148 bool bWordWrap(false); 149 150 if(bHasText) 151 { 152 // take unrotated snap rect as default, then get the 153 // unrotated text box. Rotation needs to be done centered 154 const Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect()); 155 const basegfx::B2DRange aObjectRange(aObjectBound.Left(), aObjectBound.Top(), aObjectBound.Right(), aObjectBound.Bottom()); 156 157 // #i101684# get the text range unrotated and absolute to the object range 158 const basegfx::B2DRange aTextRange(getCorrectedTextBoundRect()); 159 160 // give text object a size 161 aTextBoxMatrix.scale(aTextRange.getWidth(), aTextRange.getHeight()); 162 163 // check if we have a rotation/shear at all to take care of 164 const double fExtraTextRotation(GetCustomShapeObj().GetExtraTextRotation()); 165 const GeoStat& rGeoStat(GetCustomShapeObj().GetGeoStat()); 166 167 if(rGeoStat.nShearWink || rGeoStat.nDrehWink || !basegfx::fTools::equalZero(fExtraTextRotation)) 168 { 169 if(aObjectRange != aTextRange) 170 { 171 // move relative to unrotated object range 172 aTextBoxMatrix.translate( 173 aTextRange.getMinX() - aObjectRange.getMinimum().getX(), 174 aTextRange.getMinY() - aObjectRange.getMinimum().getY()); 175 } 176 177 if(!basegfx::fTools::equalZero(fExtraTextRotation)) 178 { 179 basegfx::B2DVector aTranslation( 180 ( aTextRange.getWidth() / 2 ) + ( aTextRange.getMinX() - aObjectRange.getMinimum().getX() ), 181 ( aTextRange.getHeight() / 2 ) + ( aTextRange.getMinY() - aObjectRange.getMinimum().getY() ) ); 182 aTextBoxMatrix.translate( -aTranslation.getX(), -aTranslation.getY() ); 183 aTextBoxMatrix.rotate((360.0 - fExtraTextRotation) * F_PI180); 184 aTextBoxMatrix.translate( aTranslation.getX(), aTranslation.getY() ); 185 } 186 187 if(rGeoStat.nShearWink) 188 { 189 aTextBoxMatrix.shearX(tan((36000 - rGeoStat.nShearWink) * F_PI18000)); 190 } 191 192 if(rGeoStat.nDrehWink) 193 { 194 aTextBoxMatrix.rotate((36000 - rGeoStat.nDrehWink) * F_PI18000); 195 } 196 197 // give text it's target position 198 aTextBoxMatrix.translate(aObjectRange.getMinimum().getX(), aObjectRange.getMinimum().getY()); 199 } 200 else 201 { 202 aTextBoxMatrix.translate(aTextRange.getMinX(), aTextRange.getMinY()); 203 } 204 205 // check if SdrTextWordWrapItem is set 206 bWordWrap = ((SdrTextWordWrapItem&)(GetCustomShapeObj().GetMergedItem(SDRATTR_TEXT_WORDWRAP))).GetValue(); 207 } 208 209 // create primitive 210 const drawinglayer::primitive2d::Primitive2DReference xReference( 211 new drawinglayer::primitive2d::SdrCustomShapePrimitive2D( 212 aAttribute, 213 xGroup, 214 aTextBoxMatrix, 215 bWordWrap, 216 b3DShape, 217 false)); // #SJ# New parameter to force to clipped BlockText for SC 218 xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); 219 } 220 221 // #119863# always append an invisible outline for the cases where no visible content exists 222 if(true) 223 { 224 const Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect()); 225 const basegfx::B2DRange aObjectRange( 226 aObjectBound.Left(), aObjectBound.Top(), 227 aObjectBound.Right(), aObjectBound.Bottom()); 228 229 // create object matrix 230 const GeoStat& rGeoStat(GetCustomShapeObj().GetGeoStat()); 231 const double fShearX(rGeoStat.nShearWink ? tan((36000 - rGeoStat.nShearWink) * F_PI18000) : 0.0); 232 const double fRotate(rGeoStat.nDrehWink ? (36000 - rGeoStat.nDrehWink) * F_PI18000 : 0.0); 233 const basegfx::B2DHomMatrix aObjectMatrix(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix( 234 aObjectRange.getWidth(), aObjectRange.getHeight(), fShearX, fRotate, 235 aObjectRange.getMinX(), aObjectRange.getMinY())); 236 237 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, 238 drawinglayer::primitive2d::createHiddenGeometryPrimitives2D( 239 false, 240 aObjectMatrix)); 241 } 242 243 return xRetval; 244 } 245 } // end of namespace contact 246 } // end of namespace sdr 247 248 ////////////////////////////////////////////////////////////////////////////// 249 // eof 250