LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / canvas / source / tools / canvascustomspritehelper.cxx
blobc56980bf2ad8237c591fbc128cb277280f8d7d17
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <com/sun/star/rendering/XPolyPolygon2D.hpp>
23 #include <com/sun/star/geometry/RealSize2D.hpp>
24 #include <com/sun/star/rendering/XBitmap.hpp>
25 #include <com/sun/star/geometry/IntegerSize2D.hpp>
26 #include <basegfx/matrix/b2dhommatrix.hxx>
27 #include <basegfx/point/b2dpoint.hxx>
28 #include <basegfx/polygon/b2dpolygontools.hxx>
29 #include <basegfx/polygon/b2dpolypolygontools.hxx>
30 #include <basegfx/utils/canvastools.hxx>
31 #include <basegfx/vector/b2dsize.hxx>
32 #include <rtl/math.hxx>
33 #include <tools/diagnose_ex.h>
35 #include <base/canvascustomspritehelper.hxx>
36 #include <canvas/canvastools.hxx>
38 using namespace ::com::sun::star;
41 namespace canvas
43 bool CanvasCustomSpriteHelper::updateClipState( const Sprite::Reference& rSprite )
45 if( !mxClipPoly.is() )
47 // empty clip polygon -> everything is visible now
48 maCurrClipBounds.reset();
49 mbIsCurrClipRectangle = true;
51 else
53 const sal_Int32 nNumClipPolygons( mxClipPoly->getNumberOfPolygons() );
55 // clip is not empty - determine actual update area
56 ::basegfx::B2DPolyPolygon aClipPath(
57 polyPolygonFromXPolyPolygon2D( mxClipPoly ) );
59 // apply sprite transformation also to clip!
60 aClipPath.transform( maTransform );
62 // clip which is about to be set, expressed as a
63 // b2drectangle
64 const ::basegfx::B2DRectangle& rClipBounds(
65 ::basegfx::utils::getRange( aClipPath ) );
67 const ::basegfx::B2DRectangle aBounds( 0.0, 0.0,
68 maSize.getX(),
69 maSize.getY() );
71 // rectangular area which is actually covered by the sprite.
72 // coordinates are relative to the sprite origin.
73 ::basegfx::B2DRectangle aSpriteRectPixel;
74 ::canvas::tools::calcTransformedRectBounds( aSpriteRectPixel,
75 aBounds,
76 maTransform );
78 // aClipBoundsA = new clip bound rect, intersected
79 // with sprite area
80 ::basegfx::B2DRectangle aClipBoundsA(rClipBounds);
81 aClipBoundsA.intersect( aSpriteRectPixel );
83 if( nNumClipPolygons != 1 )
85 // clip cannot be a single rectangle -> cannot
86 // optimize update
87 mbIsCurrClipRectangle = false;
88 maCurrClipBounds = aClipBoundsA;
90 else
92 // new clip could be a single rectangle - check
93 // that now:
94 const bool bNewClipIsRect(
95 ::basegfx::utils::isRectangle( aClipPath.getB2DPolygon(0) ) );
97 // both new and old clip are truly rectangles
98 // - can now take the optimized path
99 const bool bUseOptimizedUpdate( bNewClipIsRect &&
100 mbIsCurrClipRectangle );
102 const ::basegfx::B2DRectangle aOldBounds( maCurrClipBounds );
104 // store new current clip type
105 maCurrClipBounds = aClipBoundsA;
106 mbIsCurrClipRectangle = bNewClipIsRect;
108 if( mbActive &&
109 bUseOptimizedUpdate )
111 // aClipBoundsB = maCurrClipBounds, i.e. last
112 // clip, intersected with sprite area
113 std::vector< ::basegfx::B2DRectangle > aClipDifferences;
115 // get all rectangles covered by exactly one
116 // of the polygons (aka XOR)
117 ::basegfx::computeSetDifference(aClipDifferences,
118 aClipBoundsA,
119 aOldBounds);
121 // aClipDifferences now contains the final
122 // update areas, coordinates are still relative
123 // to the sprite origin. before submitting
124 // this area to 'updateSprite()' we need to
125 // translate this area to the final position,
126 // coordinates need to be relative to the
127 // spritecanvas.
128 for( const auto& rClipDiff : aClipDifferences )
130 mpSpriteCanvas->updateSprite(
131 rSprite,
132 maPosition,
133 ::basegfx::B2DRectangle(
134 maPosition + rClipDiff.getMinimum(),
135 maPosition + rClipDiff.getMaximum() ) );
138 // update calls all done
139 return true;
144 // caller needs to perform update calls
145 return false;
148 CanvasCustomSpriteHelper::CanvasCustomSpriteHelper() :
149 mfPriority(0.0),
150 mfAlpha(0.0),
151 mbActive(false),
152 mbIsCurrClipRectangle(true),
153 mbIsContentFullyOpaque( false ),
154 mbTransformDirty( true )
158 void CanvasCustomSpriteHelper::init( const geometry::RealSize2D& rSpriteSize,
159 const SpriteSurface::Reference& rOwningSpriteCanvas )
161 ENSURE_OR_THROW( rOwningSpriteCanvas,
162 "CanvasCustomSpriteHelper::init(): Invalid owning sprite canvas" );
164 mpSpriteCanvas = rOwningSpriteCanvas;
165 maSize.setX( std::max( 1.0,
166 ceil( rSpriteSize.Width ) ) ); // round up to nearest int,
167 // enforce sprite to have at
168 // least (1,1) pixel size
169 maSize.setY( std::max( 1.0,
170 ceil( rSpriteSize.Height ) ) );
173 void CanvasCustomSpriteHelper::disposing()
175 mpSpriteCanvas.clear();
178 void CanvasCustomSpriteHelper::clearingContent( const Sprite::Reference& /*rSprite*/ )
180 // about to clear content to fully transparent
181 mbIsContentFullyOpaque = false;
184 void CanvasCustomSpriteHelper::checkDrawBitmap( const Sprite::Reference& rSprite,
185 const uno::Reference< rendering::XBitmap >& xBitmap,
186 const rendering::ViewState& viewState,
187 const rendering::RenderState& renderState )
189 // check whether bitmap is non-alpha, and whether its
190 // transformed size covers the whole sprite.
191 if( xBitmap->hasAlpha() )
192 return;
194 const geometry::IntegerSize2D& rInputSize(
195 xBitmap->getSize() );
196 const ::basegfx::B2DSize& rOurSize(
197 rSprite->getSizePixel() );
199 ::basegfx::B2DHomMatrix aTransform;
200 if( tools::isInside(
201 ::basegfx::B2DRectangle( 0.0,0.0,
202 rOurSize.getX(),
203 rOurSize.getY() ),
204 ::basegfx::B2DRectangle( 0.0,0.0,
205 rInputSize.Width,
206 rInputSize.Height ),
207 ::canvas::tools::mergeViewAndRenderTransform(aTransform,
208 viewState,
209 renderState) ) )
211 // bitmap is opaque and will fully cover the sprite,
212 // set flag appropriately
213 mbIsContentFullyOpaque = true;
217 void CanvasCustomSpriteHelper::setAlpha( const Sprite::Reference& rSprite,
218 double alpha )
220 if( !mpSpriteCanvas )
221 return; // we're disposed
223 if( alpha != mfAlpha )
225 mfAlpha = alpha;
227 if( mbActive )
229 mpSpriteCanvas->updateSprite( rSprite,
230 maPosition,
231 getUpdateArea() );
236 void CanvasCustomSpriteHelper::move( const Sprite::Reference& rSprite,
237 const geometry::RealPoint2D& aNewPos,
238 const rendering::ViewState& viewState,
239 const rendering::RenderState& renderState )
241 if( !mpSpriteCanvas )
242 return; // we're disposed
244 ::basegfx::B2DHomMatrix aTransform;
245 ::canvas::tools::mergeViewAndRenderTransform(aTransform,
246 viewState,
247 renderState);
249 // convert position to device pixel
250 ::basegfx::B2DPoint aPoint(
251 ::basegfx::unotools::b2DPointFromRealPoint2D(aNewPos) );
252 aPoint *= aTransform;
254 if( aPoint == maPosition )
255 return;
257 const ::basegfx::B2DRectangle& rBounds
258 = getUpdateArea( ::basegfx::B2DRectangle( 0.0, 0.0,
259 maSize.getX(),
260 maSize.getY() ) );
262 if( mbActive )
264 mpSpriteCanvas->moveSprite( rSprite,
265 rBounds.getMinimum(),
266 rBounds.getMinimum() - maPosition + aPoint,
267 rBounds.getRange() );
270 maPosition = aPoint;
273 void CanvasCustomSpriteHelper::transform( const Sprite::Reference& rSprite,
274 const geometry::AffineMatrix2D& aTransformation )
276 ::basegfx::B2DHomMatrix aMatrix;
277 ::basegfx::unotools::homMatrixFromAffineMatrix(aMatrix,
278 aTransformation);
280 if( maTransform == aMatrix )
281 return;
283 // retrieve bounds before and after transformation change.
284 const ::basegfx::B2DRectangle& rPrevBounds( getUpdateArea() );
286 maTransform = aMatrix;
288 if( !updateClipState( rSprite ) &&
289 mbActive )
291 mpSpriteCanvas->updateSprite( rSprite,
292 maPosition,
293 rPrevBounds );
294 mpSpriteCanvas->updateSprite( rSprite,
295 maPosition,
296 getUpdateArea() );
299 mbTransformDirty = true;
302 void CanvasCustomSpriteHelper::clip( const Sprite::Reference& rSprite,
303 const uno::Reference< rendering::XPolyPolygon2D >& xClip )
305 // NULL xClip explicitly allowed here (to clear clipping)
307 // retrieve bounds before and after clip change.
308 const ::basegfx::B2DRectangle& rPrevBounds( getUpdateArea() );
310 mxClipPoly = xClip;
312 if( !updateClipState( rSprite ) &&
313 mbActive )
315 mpSpriteCanvas->updateSprite( rSprite,
316 maPosition,
317 rPrevBounds );
318 mpSpriteCanvas->updateSprite( rSprite,
319 maPosition,
320 getUpdateArea() );
324 void CanvasCustomSpriteHelper::setPriority( const Sprite::Reference& rSprite,
325 double nPriority )
327 if( !mpSpriteCanvas )
328 return; // we're disposed
330 if( nPriority != mfPriority )
332 mfPriority = nPriority;
334 if( mbActive )
336 mpSpriteCanvas->updateSprite( rSprite,
337 maPosition,
338 getUpdateArea() );
343 void CanvasCustomSpriteHelper::show( const Sprite::Reference& rSprite )
345 if( !mpSpriteCanvas )
346 return; // we're disposed
348 if( mbActive )
349 return;
351 mpSpriteCanvas->showSprite( rSprite );
352 mbActive = true;
354 // TODO(P1): if clip is the NULL clip (nothing visible),
355 // also save us the update call.
357 if( mfAlpha != 0.0 )
359 mpSpriteCanvas->updateSprite( rSprite,
360 maPosition,
361 getUpdateArea() );
365 void CanvasCustomSpriteHelper::hide( const Sprite::Reference& rSprite )
367 if( !mpSpriteCanvas )
368 return; // we're disposed
370 if( !mbActive )
371 return;
373 mpSpriteCanvas->hideSprite( rSprite );
374 mbActive = false;
376 // TODO(P1): if clip is the NULL clip (nothing visible),
377 // also save us the update call.
379 if( mfAlpha != 0.0 )
381 mpSpriteCanvas->updateSprite( rSprite,
382 maPosition,
383 getUpdateArea() );
387 bool CanvasCustomSpriteHelper::isAreaUpdateOpaque( const ::basegfx::B2DRange& rUpdateArea ) const
389 if( !mbIsCurrClipRectangle ||
390 !mbIsContentFullyOpaque ||
391 !::rtl::math::approxEqual(mfAlpha, 1.0) )
393 // sprite either transparent, or clip rect does not
394 // represent exact bounds -> update might not be fully
395 // opaque
396 return false;
398 else
400 // make sure sprite rect fully covers update area -
401 // although the update area originates from the sprite,
402 // it's by no means guaranteed that it's limited to this
403 // sprite's update area - after all, other sprites might
404 // have been merged, or this sprite is moving.
405 return getUpdateArea().isInside( rUpdateArea );
409 ::basegfx::B2DRange CanvasCustomSpriteHelper::getUpdateArea( const ::basegfx::B2DRange& rBounds ) const
411 // Internal! Only call with locked object mutex!
412 ::basegfx::B2DHomMatrix aTransform( maTransform );
413 aTransform.translate( maPosition.getX(),
414 maPosition.getY() );
416 // transform bounds at origin, as the sprite transformation is
417 // formulated that way
418 ::basegfx::B2DRectangle aTransformedBounds;
419 return ::canvas::tools::calcTransformedRectBounds( aTransformedBounds,
420 rBounds,
421 aTransform );
424 ::basegfx::B2DRange CanvasCustomSpriteHelper::getUpdateArea() const
426 // Internal! Only call with locked object mutex!
428 // return effective sprite rect, i.e. take active clip into
429 // account
430 if( maCurrClipBounds.isEmpty() )
431 return getUpdateArea( ::basegfx::B2DRectangle( 0.0, 0.0,
432 maSize.getX(),
433 maSize.getY() ) );
434 else
435 return ::basegfx::B2DRectangle(
436 maPosition + maCurrClipBounds.getMinimum(),
437 maPosition + maCurrClipBounds.getMaximum() );
441 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */