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_drawinglayer.hxx" 26 27 #include <drawinglayer/primitive2d/texteffectprimitive2d.hxx> 28 #include <drawinglayer/geometry/viewinformation2d.hxx> 29 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> 30 #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 31 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> 32 #include <basegfx/matrix/b2dhommatrixtools.hxx> 33 34 ////////////////////////////////////////////////////////////////////////////// 35 36 namespace drawinglayer 37 { 38 namespace primitive2d 39 { 40 static double fDiscreteSize(1.1); 41 42 Primitive2DSequence TextEffectPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const 43 { 44 Primitive2DSequence aRetval; 45 46 // get the distance of one discrete units from target display. Use between 1.0 and sqrt(2) to 47 // have good results on rotated objects, too 48 const basegfx::B2DVector aDistance(rViewInformation.getInverseObjectToViewTransformation() * 49 basegfx::B2DVector(fDiscreteSize, fDiscreteSize)); 50 const basegfx::B2DVector aDiagonalDistance(aDistance * (1.0 / 1.44)); 51 52 switch(getTextEffectStyle2D()) 53 { 54 case TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED: 55 case TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED: 56 case TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT: 57 case TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED_DEFAULT: 58 { 59 // prepare transform of sub-group back to (0,0) and align to X-Axis 60 basegfx::B2DHomMatrix aBackTransform(basegfx::tools::createTranslateB2DHomMatrix( 61 -getRotationCenter().getX(), -getRotationCenter().getY())); 62 aBackTransform.rotate(-getDirection()); 63 64 // prepare transform of sub-group back to it's position and rotation 65 basegfx::B2DHomMatrix aForwardTransform(basegfx::tools::createRotateB2DHomMatrix(getDirection())); 66 aForwardTransform.translate(getRotationCenter().getX(), getRotationCenter().getY()); 67 68 // create transformation for one discrete unit 69 const bool bEmbossed( 70 TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED == getTextEffectStyle2D() 71 || TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT == getTextEffectStyle2D()); 72 const bool bDefaultTextColor( 73 TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT == getTextEffectStyle2D() 74 || TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED_DEFAULT == getTextEffectStyle2D()); 75 basegfx::B2DHomMatrix aTransform(aBackTransform); 76 aRetval.realloc(2); 77 78 if(bEmbossed) 79 { 80 // to bottom-right 81 aTransform.translate(aDiagonalDistance.getX(), aDiagonalDistance.getY()); 82 } 83 else 84 { 85 // to top-left 86 aTransform.translate(-aDiagonalDistance.getX(), -aDiagonalDistance.getY()); 87 } 88 89 aTransform *= aForwardTransform; 90 91 if(bDefaultTextColor) 92 { 93 // emboss/engrave in black, original forced to white 94 const basegfx::BColorModifier aBColorModifierToGray(basegfx::BColor(0.0)); 95 const Primitive2DReference xModifiedColor(new ModifiedColorPrimitive2D(getTextContent(), aBColorModifierToGray)); 96 aRetval[0] = Primitive2DReference(new TransformPrimitive2D(aTransform, Primitive2DSequence(&xModifiedColor, 1))); 97 98 // add original, too 99 const basegfx::BColorModifier aBColorModifierToWhite(basegfx::BColor(1.0)); 100 aRetval[1] = Primitive2DReference(new ModifiedColorPrimitive2D(getTextContent(), aBColorModifierToWhite)); 101 } 102 else 103 { 104 // emboss/engrave in gray, keep original's color 105 const basegfx::BColorModifier aBColorModifierToGray(basegfx::BColor(0.75)); // 192 106 const Primitive2DReference xModifiedColor(new ModifiedColorPrimitive2D(getTextContent(), aBColorModifierToGray)); 107 aRetval[0] = Primitive2DReference(new TransformPrimitive2D(aTransform, Primitive2DSequence(&xModifiedColor, 1))); 108 109 // add original, too 110 aRetval[1] = Primitive2DReference(new GroupPrimitive2D(getTextContent())); 111 } 112 113 break; 114 } 115 case TEXTEFFECTSTYLE2D_OUTLINE: 116 { 117 // create transform primitives in all directions 118 basegfx::B2DHomMatrix aTransform; 119 aRetval.realloc(9); 120 121 aTransform.set(0, 2, aDistance.getX()); 122 aTransform.set(1, 2, 0.0); 123 aRetval[0] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent())); 124 125 aTransform.set(0, 2, aDiagonalDistance.getX()); 126 aTransform.set(1, 2, aDiagonalDistance.getY()); 127 aRetval[1] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent())); 128 129 aTransform.set(0, 2, 0.0); 130 aTransform.set(1, 2, aDistance.getY()); 131 aRetval[2] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent())); 132 133 aTransform.set(0, 2, -aDiagonalDistance.getX()); 134 aTransform.set(1, 2, aDiagonalDistance.getY()); 135 aRetval[3] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent())); 136 137 aTransform.set(0, 2, -aDistance.getX()); 138 aTransform.set(1, 2, 0.0); 139 aRetval[4] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent())); 140 141 aTransform.set(0, 2, -aDiagonalDistance.getX()); 142 aTransform.set(1, 2, -aDiagonalDistance.getY()); 143 aRetval[5] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent())); 144 145 aTransform.set(0, 2, 0.0); 146 aTransform.set(1, 2, -aDistance.getY()); 147 aRetval[6] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent())); 148 149 aTransform.set(0, 2, aDiagonalDistance.getX()); 150 aTransform.set(1, 2, -aDiagonalDistance.getY()); 151 aRetval[7] = Primitive2DReference(new TransformPrimitive2D(aTransform, getTextContent())); 152 153 // at last, place original over it, but force to white 154 const basegfx::BColorModifier aBColorModifierToWhite(basegfx::BColor(1.0, 1.0, 1.0)); 155 aRetval[8] = Primitive2DReference(new ModifiedColorPrimitive2D(getTextContent(), aBColorModifierToWhite)); 156 157 break; 158 } 159 } 160 161 return aRetval; 162 } 163 164 TextEffectPrimitive2D::TextEffectPrimitive2D( 165 const Primitive2DSequence& rTextContent, 166 const basegfx::B2DPoint& rRotationCenter, 167 double fDirection, 168 TextEffectStyle2D eTextEffectStyle2D) 169 : BufferedDecompositionPrimitive2D(), 170 maTextContent(rTextContent), 171 maRotationCenter(rRotationCenter), 172 mfDirection(fDirection), 173 meTextEffectStyle2D(eTextEffectStyle2D) 174 { 175 } 176 177 bool TextEffectPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const 178 { 179 if(BasePrimitive2D::operator==(rPrimitive)) 180 { 181 const TextEffectPrimitive2D& rCompare = (TextEffectPrimitive2D&)rPrimitive; 182 183 return (getTextContent() == rCompare.getTextContent() 184 && getRotationCenter() == rCompare.getRotationCenter() 185 && getDirection() == rCompare.getDirection() 186 && getTextEffectStyle2D() == rCompare.getTextEffectStyle2D()); 187 } 188 189 return false; 190 } 191 192 basegfx::B2DRange TextEffectPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const 193 { 194 // get range of content and grow by used fDiscreteSize. That way it is not necessary to ask 195 // the whole decomposition for it's ranges (which may be expensive with outline mode which 196 // then will ask 9 times at nearly the same content. This may even be refined here using the 197 // TextEffectStyle information, e.g. for TEXTEFFECTSTYLE2D_RELIEF the grow needs only to 198 // be in two directions 199 basegfx::B2DRange aRetval(getB2DRangeFromPrimitive2DSequence(getTextContent(), rViewInformation)); 200 aRetval.grow(fDiscreteSize); 201 202 return aRetval; 203 } 204 205 Primitive2DSequence TextEffectPrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const 206 { 207 ::osl::MutexGuard aGuard( m_aMutex ); 208 209 if(getBuffered2DDecomposition().hasElements()) 210 { 211 if(maLastObjectToViewTransformation != rViewInformation.getObjectToViewTransformation()) 212 { 213 // conditions of last local decomposition have changed, delete 214 const_cast< TextEffectPrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DSequence()); 215 } 216 } 217 218 if(!getBuffered2DDecomposition().hasElements()) 219 { 220 // remember ViewRange and ViewTransformation 221 const_cast< TextEffectPrimitive2D* >(this)->maLastObjectToViewTransformation = rViewInformation.getObjectToViewTransformation(); 222 } 223 224 // use parent implementation 225 return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation); 226 } 227 228 // provide unique ID 229 ImplPrimitrive2DIDBlock(TextEffectPrimitive2D, PRIMITIVE2D_ID_TEXTEFFECTPRIMITIVE2D) 230 231 } // end of namespace primitive2d 232 } // end of namespace drawinglayer 233 234 ////////////////////////////////////////////////////////////////////////////// 235 // eof 236