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