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