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/textlayoutdevice.hxx> 28 #include <vcl/timer.hxx> 29 #include <vcl/virdev.hxx> 30 #include <vcl/font.hxx> 31 #include <vcl/metric.hxx> 32 #include <i18npool/mslangid.hxx> 33 #include <drawinglayer/primitive2d/textprimitive2d.hxx> 34 #include <vcl/svapp.hxx> 35 36 ////////////////////////////////////////////////////////////////////////////// 37 // VDev RevDevice provider 38 39 namespace 40 { 41 class ImpTimedRefDev : public Timer 42 { 43 ImpTimedRefDev** mppStaticPointerOnMe; 44 VirtualDevice* mpVirDev; 45 sal_uInt32 mnUseCount; 46 47 public: 48 ImpTimedRefDev(ImpTimedRefDev** ppStaticPointerOnMe); 49 ~ImpTimedRefDev(); 50 virtual void Timeout(); 51 52 VirtualDevice& acquireVirtualDevice(); 53 void releaseVirtualDevice(); 54 }; 55 ImpTimedRefDev(ImpTimedRefDev ** ppStaticPointerOnMe)56 ImpTimedRefDev::ImpTimedRefDev(ImpTimedRefDev** ppStaticPointerOnMe) 57 : mppStaticPointerOnMe(ppStaticPointerOnMe), 58 mpVirDev(0L), 59 mnUseCount(0L) 60 { 61 SetTimeout(3L * 60L * 1000L); // three minutes 62 Start(); 63 } 64 ~ImpTimedRefDev()65 ImpTimedRefDev::~ImpTimedRefDev() 66 { 67 OSL_ENSURE(0L == mnUseCount, "destruction of a still used ImpTimedRefDev (!)"); 68 69 if(mppStaticPointerOnMe && *mppStaticPointerOnMe) 70 { 71 *mppStaticPointerOnMe = 0L; 72 } 73 74 if(mpVirDev) 75 { 76 delete mpVirDev; 77 } 78 } 79 Timeout()80 void ImpTimedRefDev::Timeout() 81 { 82 // for obvious reasons, do not call anything after this 83 delete (this); 84 } 85 acquireVirtualDevice()86 VirtualDevice& ImpTimedRefDev::acquireVirtualDevice() 87 { 88 if(!mpVirDev) 89 { 90 mpVirDev = new VirtualDevice(); 91 mpVirDev->SetReferenceDevice( VirtualDevice::REFDEV_MODE_MSO1 ); 92 } 93 94 if(!mnUseCount) 95 { 96 Stop(); 97 } 98 99 mnUseCount++; 100 101 return *mpVirDev; 102 } 103 releaseVirtualDevice()104 void ImpTimedRefDev::releaseVirtualDevice() 105 { 106 OSL_ENSURE(mnUseCount, "mismatch call number to releaseVirtualDevice() (!)"); 107 mnUseCount--; 108 109 if(!mnUseCount) 110 { 111 Start(); 112 } 113 } 114 } // end of anonymous namespace 115 116 ////////////////////////////////////////////////////////////////////////////// 117 // access to one global ImpTimedRefDev incarnation in namespace drawinglayer::primitive 118 119 namespace drawinglayer 120 { 121 namespace primitive2d 122 { 123 // static pointer here 124 static ImpTimedRefDev* pImpGlobalRefDev = 0L; 125 126 // static methods here acquireGlobalVirtualDevice()127 VirtualDevice& acquireGlobalVirtualDevice() 128 { 129 if(!pImpGlobalRefDev) 130 { 131 pImpGlobalRefDev = new ImpTimedRefDev(&pImpGlobalRefDev); 132 } 133 134 return pImpGlobalRefDev->acquireVirtualDevice(); 135 } 136 releaseGlobalVirtualDevice()137 void releaseGlobalVirtualDevice() 138 { 139 OSL_ENSURE(pImpGlobalRefDev, "releaseGlobalVirtualDevice() without prior acquireGlobalVirtualDevice() call(!)"); 140 pImpGlobalRefDev->releaseVirtualDevice(); 141 } 142 TextLayouterDevice()143 TextLayouterDevice::TextLayouterDevice() 144 : mrDevice(acquireGlobalVirtualDevice()) 145 { 146 } 147 ~TextLayouterDevice()148 TextLayouterDevice::~TextLayouterDevice() 149 { 150 releaseGlobalVirtualDevice(); 151 } 152 setFont(const Font & rFont)153 void TextLayouterDevice::setFont(const Font& rFont) 154 { 155 mrDevice.SetFont( rFont ); 156 } 157 setFontAttribute(const attribute::FontAttribute & rFontAttribute,double fFontScaleX,double fFontScaleY,const::com::sun::star::lang::Locale & rLocale)158 void TextLayouterDevice::setFontAttribute( 159 const attribute::FontAttribute& rFontAttribute, 160 double fFontScaleX, 161 double fFontScaleY, 162 const ::com::sun::star::lang::Locale& rLocale) 163 { 164 setFont(getVclFontFromFontAttribute( 165 rFontAttribute, 166 fFontScaleX, 167 fFontScaleY, 168 0.0, 169 rLocale)); 170 } 171 getOverlineOffset() const172 double TextLayouterDevice::getOverlineOffset() const 173 { 174 const ::FontMetric& rMetric = mrDevice.GetFontMetric(); 175 double fRet = (rMetric.GetIntLeading() / 2.0) - rMetric.GetAscent(); 176 return fRet; 177 } 178 getUnderlineOffset() const179 double TextLayouterDevice::getUnderlineOffset() const 180 { 181 const ::FontMetric& rMetric = mrDevice.GetFontMetric(); 182 double fRet = rMetric.GetDescent() / 2.0; 183 return fRet; 184 } 185 getStrikeoutOffset() const186 double TextLayouterDevice::getStrikeoutOffset() const 187 { 188 const ::FontMetric& rMetric = mrDevice.GetFontMetric(); 189 double fRet = (rMetric.GetAscent() - rMetric.GetIntLeading()) / 3.0; 190 return fRet; 191 } 192 getOverlineHeight() const193 double TextLayouterDevice::getOverlineHeight() const 194 { 195 const ::FontMetric& rMetric = mrDevice.GetFontMetric(); 196 double fRet = rMetric.GetIntLeading() / 2.5; 197 return fRet; 198 } 199 getUnderlineHeight() const200 double TextLayouterDevice::getUnderlineHeight() const 201 { 202 const ::FontMetric& rMetric = mrDevice.GetFontMetric(); 203 double fRet = rMetric.GetDescent() / 4.0; 204 return fRet; 205 } 206 getTextHeight() const207 double TextLayouterDevice::getTextHeight() const 208 { 209 return mrDevice.GetTextHeight(); 210 } 211 getTextWidth(const String & rText,sal_uInt32 nIndex,sal_uInt32 nLength) const212 double TextLayouterDevice::getTextWidth( 213 const String& rText, 214 sal_uInt32 nIndex, 215 sal_uInt32 nLength) const 216 { 217 return mrDevice.GetTextWidth(rText, nIndex, nLength); 218 } 219 getTextOutlines(basegfx::B2DPolyPolygonVector & rB2DPolyPolyVector,const String & rText,sal_uInt32 nIndex,sal_uInt32 nLength,const::std::vector<double> & rDXArray) const220 bool TextLayouterDevice::getTextOutlines( 221 basegfx::B2DPolyPolygonVector& rB2DPolyPolyVector, 222 const String& rText, 223 sal_uInt32 nIndex, 224 sal_uInt32 nLength, 225 const ::std::vector< double >& rDXArray) const 226 { 227 const sal_uInt32 nDXArrayCount(rDXArray.size()); 228 sal_uInt32 nTextLength(nLength); 229 const sal_uInt32 nStringLength(rText.Len()); 230 231 if(nTextLength + nIndex > nStringLength) 232 { 233 nTextLength = nStringLength - nIndex; 234 } 235 236 if(nDXArrayCount) 237 { 238 OSL_ENSURE(nDXArrayCount == nTextLength, "DXArray size does not correspond to text portion size (!)"); 239 std::vector< sal_Int32 > aIntegerDXArray(nDXArrayCount); 240 241 for(sal_uInt32 a(0); a < nDXArrayCount; a++) 242 { 243 aIntegerDXArray[a] = basegfx::fround(rDXArray[a]); 244 } 245 246 return mrDevice.GetTextOutlines( 247 rB2DPolyPolyVector, 248 rText, 249 nIndex, 250 nIndex, 251 nLength, 252 true, 253 0, 254 &(aIntegerDXArray[0])); 255 } 256 else 257 { 258 return mrDevice.GetTextOutlines( 259 rB2DPolyPolyVector, 260 rText, 261 nIndex, 262 nIndex, 263 nLength, 264 true, 265 0, 266 0); 267 } 268 } 269 getTextBoundRect(const String & rText,sal_uInt32 nIndex,sal_uInt32 nLength) const270 basegfx::B2DRange TextLayouterDevice::getTextBoundRect( 271 const String& rText, 272 sal_uInt32 nIndex, 273 sal_uInt32 nLength) const 274 { 275 sal_uInt32 nTextLength(nLength); 276 const sal_uInt32 nStringLength(rText.Len()); 277 278 if(nTextLength + nIndex > nStringLength) 279 { 280 nTextLength = nStringLength - nIndex; 281 } 282 283 if(nTextLength) 284 { 285 Rectangle aRect; 286 287 mrDevice.GetTextBoundRect( 288 aRect, 289 rText, 290 nIndex, 291 nIndex, 292 nLength); 293 294 // #i104432#, #i102556# take empty results into account 295 if(!aRect.IsEmpty()) 296 { 297 return basegfx::B2DRange( 298 aRect.Left(), aRect.Top(), 299 aRect.Right(), aRect.Bottom()); 300 } 301 } 302 303 return basegfx::B2DRange(); 304 } 305 getFontAscent() const306 double TextLayouterDevice::getFontAscent() const 307 { 308 const ::FontMetric& rMetric = mrDevice.GetFontMetric(); 309 return rMetric.GetAscent(); 310 } 311 getFontDescent() const312 double TextLayouterDevice::getFontDescent() const 313 { 314 const ::FontMetric& rMetric = mrDevice.GetFontMetric(); 315 return rMetric.GetDescent(); 316 } 317 addTextRectActions(const Rectangle & rRectangle,const String & rText,sal_uInt16 nStyle,GDIMetaFile & rGDIMetaFile) const318 void TextLayouterDevice::addTextRectActions( 319 const Rectangle& rRectangle, 320 const String& rText, 321 sal_uInt16 nStyle, 322 GDIMetaFile& rGDIMetaFile) const 323 { 324 mrDevice.AddTextRectActions( 325 rRectangle, rText, nStyle, rGDIMetaFile); 326 } 327 getTextArray(const String & rText,sal_uInt32 nIndex,sal_uInt32 nLength) const328 ::std::vector< double > TextLayouterDevice::getTextArray( 329 const String& rText, 330 sal_uInt32 nIndex, 331 sal_uInt32 nLength) const 332 { 333 ::std::vector< double > aRetval; 334 sal_uInt32 nTextLength(nLength); 335 const sal_uInt32 nStringLength(rText.Len()); 336 337 if(nTextLength + nIndex > nStringLength) 338 { 339 nTextLength = nStringLength - nIndex; 340 } 341 342 if(nTextLength) 343 { 344 aRetval.reserve(nTextLength); 345 ::std::vector<sal_Int32> aDXArray( nTextLength); 346 mrDevice.GetTextArray(rText, &aDXArray[0], nIndex, nLength); 347 348 for(sal_uInt32 a(0); a < nTextLength; a++) 349 { 350 aRetval.push_back(aDXArray[a]); 351 } 352 } 353 354 return aRetval; 355 } 356 357 } // end of namespace primitive2d 358 } // end of namespace drawinglayer 359 360 ////////////////////////////////////////////////////////////////////////////// 361 // helper methods for vcl font handling 362 363 namespace drawinglayer 364 { 365 namespace primitive2d 366 { getVclFontFromFontAttribute(const attribute::FontAttribute & rFontAttribute,double fFontScaleX,double fFontScaleY,double fFontRotation,const::com::sun::star::lang::Locale & rLocale)367 Font getVclFontFromFontAttribute( 368 const attribute::FontAttribute& rFontAttribute, 369 double fFontScaleX, 370 double fFontScaleY, 371 double fFontRotation, 372 const ::com::sun::star::lang::Locale& rLocale) 373 { 374 // detect FontScaling 375 const sal_uInt32 nHeight(basegfx::fround(fabs(fFontScaleY))); 376 const sal_uInt32 nWidth(basegfx::fround(fabs(fFontScaleX))); 377 const bool bFontIsScaled(nHeight != nWidth); 378 379 #ifdef WIN32 380 // for WIN32 systems, start with creating an unscaled font. If FontScaling 381 // is wanted, that width needs to be adapted using FontMetric again to get a 382 // width of the unscaled font 383 Font aRetval( 384 rFontAttribute.getFamilyName(), 385 rFontAttribute.getStyleName(), 386 Size(0, nHeight)); 387 #else 388 // for non-WIN32 systems things are easier since these accept a Font creation 389 // with initially nWidth != nHeight for FontScaling. Despite that, use zero for 390 // FontWidth when no scaling is used to explicitly have that zero when e.g. the 391 // Font would be recorded in a MetaFile (The MetaFile FontAction WILL record a 392 // set FontWidth; import that in a WIN32 system, and trouble is there) 393 Font aRetval( 394 rFontAttribute.getFamilyName(), 395 rFontAttribute.getStyleName(), 396 Size(bFontIsScaled ? nWidth : 0, nHeight)); 397 #endif 398 // define various other FontAttribute 399 aRetval.SetAlign(ALIGN_BASELINE); 400 aRetval.SetCharSet(rFontAttribute.getSymbol() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE); 401 aRetval.SetVertical(rFontAttribute.getVertical() ? sal_True : sal_False); 402 aRetval.SetWeight(static_cast<FontWeight>(rFontAttribute.getWeight())); 403 aRetval.SetItalic(rFontAttribute.getItalic() ? ITALIC_NORMAL : ITALIC_NONE); 404 aRetval.SetOutline(rFontAttribute.getOutline()); 405 aRetval.SetPitch(rFontAttribute.getMonospaced() ? PITCH_FIXED : PITCH_VARIABLE); 406 aRetval.SetLanguage(MsLangId::convertLocaleToLanguage(rLocale)); 407 408 #ifdef WIN32 409 // for WIN32 systems, correct the FontWidth if FontScaling is used 410 if(bFontIsScaled && nHeight > 0) 411 { 412 const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aRetval)); 413 414 if(aUnscaledFontMetric.GetWidth() > 0) 415 { 416 const double fScaleFactor((double)nWidth / (double)nHeight); 417 const sal_uInt32 nScaledWidth(basegfx::fround((double)aUnscaledFontMetric.GetWidth() * fScaleFactor)); 418 aRetval.SetWidth(nScaledWidth); 419 } 420 } 421 #endif 422 // handle FontRotation (if defined) 423 if(!basegfx::fTools::equalZero(fFontRotation)) 424 { 425 sal_Int16 aRotate10th((sal_Int16)(fFontRotation * (-1800.0/F_PI))); 426 aRetval.SetOrientation(aRotate10th % 3600); 427 } 428 429 return aRetval; 430 } 431 getFontAttributeFromVclFont(basegfx::B2DVector & o_rSize,const Font & rFont,bool bRTL,bool bBiDiStrong)432 attribute::FontAttribute getFontAttributeFromVclFont( 433 basegfx::B2DVector& o_rSize, 434 const Font& rFont, 435 bool bRTL, 436 bool bBiDiStrong) 437 { 438 const attribute::FontAttribute aRetval( 439 rFont.GetName(), 440 rFont.GetStyleName(), 441 static_cast<sal_uInt16>(rFont.GetWeight()), 442 RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet(), 443 rFont.IsVertical(), 444 ITALIC_NONE != rFont.GetItalic(), 445 PITCH_FIXED == rFont.GetPitch(), 446 rFont.IsOutline(), 447 bRTL, 448 bBiDiStrong); 449 // TODO: eKerning 450 451 // set FontHeight and init to no FontScaling 452 o_rSize.setY(rFont.GetSize().getHeight() > 0 ? rFont.GetSize().getHeight() : 0); 453 o_rSize.setX(o_rSize.getY()); 454 455 #ifdef WIN32 456 // for WIN32 systems, the FontScaling at the Font is detected by 457 // checking that FontWidth != 0. When FontScaling is used, WIN32 458 // needs to do extra stuff to detect the correct width (since it's 459 // zero and not equal the font height) and it's relationship to 460 // the height 461 if(rFont.GetSize().getWidth() > 0) 462 { 463 Font aUnscaledFont(rFont); 464 aUnscaledFont.SetWidth(0); 465 const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aUnscaledFont)); 466 467 if(aUnscaledFontMetric.GetWidth() > 0) 468 { 469 const double fScaleFactor((double)rFont.GetSize().getWidth() / (double)aUnscaledFontMetric.GetWidth()); 470 o_rSize.setX(fScaleFactor * o_rSize.getY()); 471 } 472 } 473 #else 474 // For non-WIN32 systems the detection is the same, but the value 475 // is easier achieved since width == height is interpreted as no 476 // scaling. Ergo, Width == 0 means width == height, and width != 0 477 // means the scaling is in the direct relation of width to height 478 if(rFont.GetSize().getWidth() > 0) 479 { 480 o_rSize.setX((double)rFont.GetSize().getWidth()); 481 } 482 #endif 483 return aRetval; 484 } 485 } // end of namespace primitive2d 486 } // end of namespace drawinglayer 487 488 ////////////////////////////////////////////////////////////////////////////// 489 // eof 490