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_canvas.hxx" 30 31 #include "surface.hxx" 32 #include <basegfx/polygon/b2dpolygonclipper.hxx> 33 #include <basegfx/matrix/b2dhommatrixtools.hxx> 34 #include <comphelper/scopeguard.hxx> 35 #include <boost/bind.hpp> 36 37 namespace canvas 38 { 39 40 ////////////////////////////////////////////////////////////////////////////////// 41 // Surface::Surface 42 ////////////////////////////////////////////////////////////////////////////////// 43 44 Surface::Surface( const PageManagerSharedPtr& rPageManager, 45 const IColorBufferSharedPtr& rColorBuffer, 46 const ::basegfx::B2IPoint& rPos, 47 const ::basegfx::B2ISize& rSize ) : 48 mpColorBuffer(rColorBuffer), 49 mpPageManager(rPageManager), 50 mpFragment(), 51 maSourceOffset(rPos), 52 maSize(rSize), 53 mbIsDirty(true) 54 { 55 } 56 57 ////////////////////////////////////////////////////////////////////////////////// 58 // Surface::~Surface 59 ////////////////////////////////////////////////////////////////////////////////// 60 61 Surface::~Surface() 62 { 63 if(mpFragment) 64 mpPageManager->free(mpFragment); 65 } 66 67 ////////////////////////////////////////////////////////////////////////////////// 68 // Surface::getUVCoords 69 ////////////////////////////////////////////////////////////////////////////////// 70 71 void Surface::setColorBufferDirty() 72 { 73 mbIsDirty=true; 74 } 75 76 ////////////////////////////////////////////////////////////////////////////////// 77 // Surface::getUVCoords 78 ////////////////////////////////////////////////////////////////////////////////// 79 80 basegfx::B2DRectangle Surface::getUVCoords() const 81 { 82 ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize()); 83 ::basegfx::B2IPoint aDestOffset; 84 if( mpFragment ) 85 aDestOffset = mpFragment->getPos(); 86 87 const double pw( aPageSize.getX() ); 88 const double ph( aPageSize.getY() ); 89 const double ox( aDestOffset.getX() ); 90 const double oy( aDestOffset.getY() ); 91 const double sx( maSize.getX() ); 92 const double sy( maSize.getY() ); 93 94 return ::basegfx::B2DRectangle( ox/pw, 95 oy/ph, 96 (ox+sx)/pw, 97 (oy+sy)/ph ); 98 } 99 100 ////////////////////////////////////////////////////////////////////////////////// 101 // Surface::getUVCoords 102 ////////////////////////////////////////////////////////////////////////////////// 103 104 basegfx::B2DRectangle Surface::getUVCoords( const ::basegfx::B2IPoint& rPos, 105 const ::basegfx::B2ISize& rSize ) const 106 { 107 ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize()); 108 109 const double pw( aPageSize.getX() ); 110 const double ph( aPageSize.getY() ); 111 const double ox( rPos.getX() ); 112 const double oy( rPos.getY() ); 113 const double sx( rSize.getX() ); 114 const double sy( rSize.getY() ); 115 116 return ::basegfx::B2DRectangle( ox/pw, 117 oy/ph, 118 (ox+sx)/pw, 119 (oy+sy)/ph ); 120 } 121 122 ////////////////////////////////////////////////////////////////////////////////// 123 // Surface::draw 124 ////////////////////////////////////////////////////////////////////////////////// 125 126 bool Surface::draw( double fAlpha, 127 const ::basegfx::B2DPoint& rPos, 128 const ::basegfx::B2DHomMatrix& rTransform ) 129 { 130 IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule()); 131 132 RenderModuleGuard aGuard( pRenderModule ); 133 134 prepareRendering(); 135 136 // convert size to normalized device coordinates 137 const ::basegfx::B2DRectangle& rUV( getUVCoords() ); 138 139 const double u1(rUV.getMinX()); 140 const double v1(rUV.getMinY()); 141 const double u2(rUV.getMaxX()); 142 const double v2(rUV.getMaxY()); 143 144 // concat transforms 145 // 1) offset of surface subarea 146 // 2) surface transform 147 // 3) translation to output position [rPos] 148 // 4) scale to normalized device coordinates 149 // 5) flip y-axis 150 // 6) translate to account for viewport transform 151 basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix( 152 maSourceOffset.getX(), maSourceOffset.getY())); 153 aTransform = aTransform * rTransform; 154 aTransform.translate(::basegfx::fround(rPos.getX()), 155 ::basegfx::fround(rPos.getY())); 156 157 /* 158 ###################################### 159 ###################################### 160 ###################################### 161 162 Y 163 ^+1 164 | 165 2 | 3 166 x------------x 167 | | | 168 | | | 169 ------|-----O------|------>X 170 -1 | | | +1 171 | | | 172 x------------x 173 1 | 0 174 | 175 |-1 176 177 ###################################### 178 ###################################### 179 ###################################### 180 */ 181 182 const ::basegfx::B2DPoint& p0(aTransform * ::basegfx::B2DPoint(maSize.getX(),maSize.getY())); 183 const ::basegfx::B2DPoint& p1(aTransform * ::basegfx::B2DPoint(0.0,maSize.getY())); 184 const ::basegfx::B2DPoint& p2(aTransform * ::basegfx::B2DPoint(0.0,0.0)); 185 const ::basegfx::B2DPoint& p3(aTransform * ::basegfx::B2DPoint(maSize.getX(),0.0)); 186 187 canvas::Vertex vertex; 188 vertex.r = 1.0f; 189 vertex.g = 1.0f; 190 vertex.b = 1.0f; 191 vertex.a = static_cast<float>(fAlpha); 192 vertex.z = 0.0f; 193 194 { 195 pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_QUAD ); 196 197 // issue an endPrimitive() when leaving the scope 198 const ::comphelper::ScopeGuard aScopeGuard( 199 boost::bind( &::canvas::IRenderModule::endPrimitive, 200 ::boost::ref(pRenderModule) ) ); 201 202 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2); 203 vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY()); 204 pRenderModule->pushVertex(vertex); 205 206 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2); 207 vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY()); 208 pRenderModule->pushVertex(vertex); 209 210 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1); 211 vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY()); 212 pRenderModule->pushVertex(vertex); 213 214 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1); 215 vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY()); 216 pRenderModule->pushVertex(vertex); 217 } 218 219 return !(pRenderModule->isError()); 220 } 221 222 ////////////////////////////////////////////////////////////////////////////////// 223 // Surface::drawRectangularArea 224 ////////////////////////////////////////////////////////////////////////////////// 225 226 bool Surface::drawRectangularArea( 227 double fAlpha, 228 const ::basegfx::B2DPoint& rPos, 229 const ::basegfx::B2DRectangle& rArea, 230 const ::basegfx::B2DHomMatrix& rTransform ) 231 { 232 if( rArea.isEmpty() ) 233 return true; // immediate exit for empty area 234 235 IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule()); 236 237 RenderModuleGuard aGuard( pRenderModule ); 238 239 prepareRendering(); 240 241 // these positions are relative to the texture 242 ::basegfx::B2IPoint aPos1( 243 ::basegfx::fround(rArea.getMinimum().getX()), 244 ::basegfx::fround(rArea.getMinimum().getY())); 245 ::basegfx::B2IPoint aPos2( 246 ::basegfx::fround(rArea.getMaximum().getX()), 247 ::basegfx::fround(rArea.getMaximum().getY()) ); 248 249 // clip the positions to the area this surface covers 250 aPos1.setX(::std::max(aPos1.getX(),maSourceOffset.getX())); 251 aPos1.setY(::std::max(aPos1.getY(),maSourceOffset.getY())); 252 aPos2.setX(::std::min(aPos2.getX(),maSourceOffset.getX()+maSize.getX())); 253 aPos2.setY(::std::min(aPos2.getY(),maSourceOffset.getY()+maSize.getY())); 254 255 // if the resulting area is empty, return immediately 256 ::basegfx::B2IVector aSize(aPos2 - aPos1); 257 if(aSize.getX() <= 0 || aSize.getY() <= 0) 258 return true; 259 260 ::basegfx::B2IPoint aDestOffset; 261 if( mpFragment ) 262 aDestOffset = mpFragment->getPos(); 263 264 // convert size to normalized device coordinates 265 const ::basegfx::B2DRectangle& rUV( 266 getUVCoords(aPos1 - maSourceOffset + aDestOffset, 267 aSize) ); 268 const double u1(rUV.getMinX()); 269 const double v1(rUV.getMinY()); 270 const double u2(rUV.getMaxX()); 271 const double v2(rUV.getMaxY()); 272 273 // concatenate transforms 274 // 1) offset of surface subarea 275 // 2) surface transform 276 // 3) translation to output position [rPos] 277 basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(aPos1.getX(), aPos1.getY())); 278 aTransform = aTransform * rTransform; 279 aTransform.translate(::basegfx::fround(rPos.getX()), 280 ::basegfx::fround(rPos.getY())); 281 282 283 /* 284 ###################################### 285 ###################################### 286 ###################################### 287 288 Y 289 ^+1 290 | 291 2 | 3 292 x------------x 293 | | | 294 | | | 295 ------|-----O------|------>X 296 -1 | | | +1 297 | | | 298 x------------x 299 1 | 0 300 | 301 |-1 302 303 ###################################### 304 ###################################### 305 ###################################### 306 */ 307 308 const ::basegfx::B2DPoint& p0(aTransform * ::basegfx::B2DPoint(aSize.getX(),aSize.getY())); 309 const ::basegfx::B2DPoint& p1(aTransform * ::basegfx::B2DPoint(0.0, aSize.getY())); 310 const ::basegfx::B2DPoint& p2(aTransform * ::basegfx::B2DPoint(0.0, 0.0)); 311 const ::basegfx::B2DPoint& p3(aTransform * ::basegfx::B2DPoint(aSize.getX(),0.0)); 312 313 canvas::Vertex vertex; 314 vertex.r = 1.0f; 315 vertex.g = 1.0f; 316 vertex.b = 1.0f; 317 vertex.a = static_cast<float>(fAlpha); 318 vertex.z = 0.0f; 319 320 { 321 pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_QUAD ); 322 323 // issue an endPrimitive() when leaving the scope 324 const ::comphelper::ScopeGuard aScopeGuard( 325 boost::bind( &::canvas::IRenderModule::endPrimitive, 326 ::boost::ref(pRenderModule) ) ); 327 328 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2); 329 vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY()); 330 pRenderModule->pushVertex(vertex); 331 332 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2); 333 vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY()); 334 pRenderModule->pushVertex(vertex); 335 336 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1); 337 vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY()); 338 pRenderModule->pushVertex(vertex); 339 340 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1); 341 vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY()); 342 pRenderModule->pushVertex(vertex); 343 } 344 345 return !(pRenderModule->isError()); 346 } 347 348 ////////////////////////////////////////////////////////////////////////////////// 349 // Surface::drawWithClip 350 ////////////////////////////////////////////////////////////////////////////////// 351 352 bool Surface::drawWithClip( double fAlpha, 353 const ::basegfx::B2DPoint& rPos, 354 const ::basegfx::B2DPolygon& rClipPoly, 355 const ::basegfx::B2DHomMatrix& rTransform ) 356 { 357 IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule()); 358 359 RenderModuleGuard aGuard( pRenderModule ); 360 361 prepareRendering(); 362 363 // untransformed surface rectangle, relative to the whole 364 // image (note: this surface might actually only be a tile of 365 // the whole image, with non-zero maSourceOffset) 366 const double x1(maSourceOffset.getX()); 367 const double y1(maSourceOffset.getY()); 368 const double w(maSize.getX()); 369 const double h(maSize.getY()); 370 const double x2(x1+w); 371 const double y2(y1+h); 372 const ::basegfx::B2DRectangle aSurfaceClipRect(x1,y1,x2,y2); 373 374 // concatenate transforms 375 // we use 'fround' here to avoid rounding errors. the vertices will 376 // be transformed by the overall transform and uv coordinates will 377 // be calculated from the result, and this is why we need to use 378 // integer coordinates here... 379 basegfx::B2DHomMatrix aTransform; 380 aTransform = aTransform * rTransform; 381 aTransform.translate(::basegfx::fround(rPos.getX()), 382 ::basegfx::fround(rPos.getY())); 383 384 /* 385 ###################################### 386 ###################################### 387 ###################################### 388 389 Y 390 ^+1 391 | 392 2 | 3 393 x------------x 394 | | | 395 | | | 396 ------|-----O------|------>X 397 -1 | | | +1 398 | | | 399 x------------x 400 1 | 0 401 | 402 |-1 403 404 ###################################### 405 ###################################### 406 ###################################### 407 */ 408 409 // uv coordinates that map the surface rectangle 410 // to the destination rectangle. 411 const ::basegfx::B2DRectangle& rUV( getUVCoords() ); 412 413 basegfx::B2DPolygon rTriangleList(basegfx::tools::clipTriangleListOnRange(rClipPoly, 414 aSurfaceClipRect)); 415 416 // Push vertices to backend renderer 417 if(const sal_uInt32 nVertexCount = rTriangleList.count()) 418 { 419 canvas::Vertex vertex; 420 vertex.r = 1.0f; 421 vertex.g = 1.0f; 422 vertex.b = 1.0f; 423 vertex.a = static_cast<float>(fAlpha); 424 vertex.z = 0.0f; 425 426 #if defined(TRIANGLE_LOG) && defined(DBG_UTIL) 427 OSL_TRACE( "Surface::draw(): numvertices %d numtriangles %d\n", 428 nVertexCount, 429 nVertexCount/3 ); 430 #endif 431 432 pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_TRIANGLE ); 433 434 // issue an endPrimitive() when leaving the scope 435 const ::comphelper::ScopeGuard aScopeGuard( 436 boost::bind( &::canvas::IRenderModule::endPrimitive, 437 ::boost::ref(pRenderModule) ) ); 438 439 for(sal_uInt32 nIndex=0; nIndex<nVertexCount; ++nIndex) 440 { 441 const basegfx::B2DPoint &aPoint = rTriangleList.getB2DPoint(nIndex); 442 basegfx::B2DPoint aTransformedPoint(aTransform * aPoint); 443 const double tu(((aPoint.getX()-aSurfaceClipRect.getMinX())*rUV.getWidth()/w)+rUV.getMinX()); 444 const double tv(((aPoint.getY()-aSurfaceClipRect.getMinY())*rUV.getHeight()/h)+rUV.getMinY()); 445 vertex.u=static_cast<float>(tu); 446 vertex.v=static_cast<float>(tv); 447 vertex.x=static_cast<float>(aTransformedPoint.getX()); 448 vertex.y=static_cast<float>(aTransformedPoint.getY()); 449 pRenderModule->pushVertex(vertex); 450 } 451 } 452 453 return !(pRenderModule->isError()); 454 } 455 456 ////////////////////////////////////////////////////////////////////////////////// 457 // Surface::prepareRendering 458 ////////////////////////////////////////////////////////////////////////////////// 459 460 void Surface::prepareRendering() 461 { 462 mpPageManager->validatePages(); 463 464 // clients requested to draw from this surface, therefore one 465 // of the above implemented concrete rendering operations 466 // was triggered. we therefore need to ask the pagemanager 467 // to allocate some space for the fragment we're dedicated to. 468 if(!(mpFragment)) 469 { 470 mpFragment = mpPageManager->allocateSpace(maSize); 471 if( mpFragment ) 472 { 473 mpFragment->setColorBuffer(mpColorBuffer); 474 mpFragment->setSourceOffset(maSourceOffset); 475 } 476 } 477 478 if( mpFragment ) 479 { 480 // now we need to 'select' the fragment, which will in turn 481 // pull informations from the image on demand. 482 // in case this fragment is still not located on any of the 483 // available pages ['naked'], we force the page manager to 484 // do it now, no way to defer this any longer... 485 if(!(mpFragment->select(mbIsDirty))) 486 mpPageManager->nakedFragment(mpFragment); 487 488 } 489 mbIsDirty=false; 490 } 491 492 ////////////////////////////////////////////////////////////////////////////////// 493 // End of file 494 ////////////////////////////////////////////////////////////////////////////////// 495 } 496 497