xref: /aoo4110/main/canvas/inc/canvas/canvastools.hxx (revision b1cdbd2c)
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 #ifndef INCLUDED_CANVAS_CANVASTOOLS_HXX
25 #define INCLUDED_CANVAS_CANVASTOOLS_HXX
26 
27 #include <rtl/math.hxx>
28 #include <com/sun/star/uno/Reference.hxx>
29 #include <com/sun/star/uno/Sequence.hxx>
30 #include <com/sun/star/uno/RuntimeException.hpp>
31 #include <com/sun/star/lang/IllegalArgumentException.hpp>
32 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
33 #include <osl/diagnose.h>
34 #include <rtl/ustring.hxx>
35 
36 #include <string.h> // for strcmp
37 #include <vector>
38 #include <limits>
39 #include <algorithm>
40 
41 
42 namespace basegfx
43 {
44     class B2DHomMatrix;
45     class B2DRange;
46     class B2IRange;
47     class B2IPoint;
48     class B2DPolyPolygon;
49 }
50 
51 namespace com { namespace sun { namespace star { namespace geometry
52 {
53     struct RealSize2D;
54     struct IntegerSize2D;
55     struct AffineMatrix2D;
56     struct Matrix2D;
57 } } } }
58 
59 namespace com { namespace sun { namespace star { namespace rendering
60 {
61     struct RenderState;
62     struct ViewState;
63     struct IntegerBitmapLayout;
64     class  XCanvas;
65     struct Texture;
66     class  XIntegerBitmapColorSpace;
67     class  XPolyPolygon2D;
68 
69     bool operator==( const RenderState&	rLHS,
70                      const RenderState& rRHS );
71 
72     bool operator==( const ViewState& rLHS,
73                      const ViewState& rRHS );
74 } } } }
75 
76 namespace com { namespace sun { namespace star { namespace awt
77 {
78     struct Rectangle;
79     class  XWindow2;
80 } } } }
81 
82 class Color;
83 
84 namespace canvas
85 {
86     namespace tools
87     {
88         /** Compute the next highest power of 2 of a 32-bit value
89 
90         	Code devised by Sean Anderson, in good ole HAKMEM
91         	tradition.
92 
93             @return 1 << (lg(x - 1) + 1)
94         */
nextPow2(sal_uInt32 x)95         inline sal_uInt32 nextPow2( sal_uInt32 x )
96         {
97             --x;
98             x |= x >> 1;
99             x |= x >> 2;
100             x |= x >> 4;
101             x |= x >> 8;
102             x |= x >> 16;
103 
104             return ++x;
105         }
106 
107 		/**
108 		 *
109 		 * Count the number of 1-bits of an n-bit value
110 		 *
111 		 */
112 
113 		// mickey's math tricks...
pow2(unsigned int c)114 		inline unsigned int pow2( unsigned int c ) { return 0x1 << c; }
mask(unsigned int c)115 		inline unsigned int mask( unsigned int c ) { return ((unsigned int)(-1)) / (pow2(pow2(c)) + 1); }
count(unsigned int x,unsigned int c)116 		inline unsigned int count( unsigned int x, unsigned int c ) { return ((x) & mask(c)) + (((x) >> (pow2(c))) & mask(c)); }
117 		template<typename T>
bitcount(T c)118 		inline unsigned int bitcount( T c ) {
119 			unsigned int nByteIndex = 0;
120 			unsigned int nNumBytes = sizeof(T)<<2;
121 			do {
122 				c=count(c,nByteIndex++);
123 				nNumBytes >>= 1;
124 			} while(nNumBytes);
125 			return c;
126 		}
bitcount32(sal_uInt32 c)127 		inline sal_uInt32 bitcount32( sal_uInt32 c ) {
128 			c=count(c,0);
129 			c=count(c,1);
130 			c=count(c,2);
131 			c=count(c,3);
132 			c=count(c,4);
133 			return c;
134 		}
135 
136         /** Round given floating point value down to next integer
137          */
roundDown(const double & rVal)138         inline sal_Int32 roundDown( const double& rVal )
139         {
140             return static_cast< sal_Int32 >( floor( rVal ) );
141         }
142 
143         /** Round given floating point value up to next integer
144          */
roundUp(const double & rVal)145         inline sal_Int32 roundUp( const double& rVal )
146         {
147             return static_cast< sal_Int32 >( ceil( rVal ) );
148         }
149 
150         /** Create a RealSize2D with both coordinate values set to +infinity
151          */
152         ::com::sun::star::geometry::RealSize2D createInfiniteSize2D();
153 
154 
155         // View- and RenderState utilities
156         // ===================================================================
157 
158         ::com::sun::star::rendering::RenderState&
159         	initRenderState( ::com::sun::star::rendering::RenderState&						renderState );
160 
161         ::com::sun::star::rendering::ViewState&
162         	initViewState( ::com::sun::star::rendering::ViewState&							viewState );
163 
164         ::basegfx::B2DHomMatrix&
165 	        getViewStateTransform( ::basegfx::B2DHomMatrix&									transform,
166                                    const ::com::sun::star::rendering::ViewState&			viewState );
167 
168         ::com::sun::star::rendering::ViewState&
169         	setViewStateTransform( ::com::sun::star::rendering::ViewState& 					viewState,
170                                    const ::basegfx::B2DHomMatrix&							transform );
171 
172         ::basegfx::B2DHomMatrix&
173         	getRenderStateTransform( ::basegfx::B2DHomMatrix&								transform,
174                                      const ::com::sun::star::rendering::RenderState&		renderState );
175 
176         ::com::sun::star::rendering::RenderState&
177         	setRenderStateTransform( ::com::sun::star::rendering::RenderState& 				renderState,
178                                      const ::basegfx::B2DHomMatrix&							transform );
179 
180         ::com::sun::star::rendering::ViewState&
181         	appendToViewState( ::com::sun::star::rendering::ViewState&						viewState,
182                                const ::basegfx::B2DHomMatrix&								transform );
183 
184         ::com::sun::star::rendering::RenderState&
185         	appendToRenderState( ::com::sun::star::rendering::RenderState&					renderState,
186                                  const ::basegfx::B2DHomMatrix&								transform );
187 
188         ::com::sun::star::rendering::ViewState&
189         	prependToViewState( ::com::sun::star::rendering::ViewState&						viewState,
190                                 const ::basegfx::B2DHomMatrix&								transform );
191 
192         ::com::sun::star::rendering::RenderState&
193         	prependToRenderState( ::com::sun::star::rendering::RenderState&					renderState,
194                                   const ::basegfx::B2DHomMatrix&							transform );
195 
196         ::basegfx::B2DHomMatrix&
197         	mergeViewAndRenderTransform( ::basegfx::B2DHomMatrix&							transform,
198                                          const ::com::sun::star::rendering::ViewState&		viewState,
199                                          const ::com::sun::star::rendering::RenderState&	renderState );
200 
201         ::com::sun::star::rendering::ViewState&
202 	        mergeViewAndRenderState( ::com::sun::star::rendering::ViewState&				resultViewState,
203                                      const ::com::sun::star::rendering::ViewState&			viewState,
204                                      const ::com::sun::star::rendering::RenderState&		renderState,
205                                      const ::com::sun::star::uno::Reference<
206                                      	::com::sun::star::rendering::XCanvas >& 			xCanvas );
207 
208 
209         // Matrix utilities
210         // ===================================================================
211 
212         ::com::sun::star::geometry::AffineMatrix2D&
213         	setIdentityAffineMatrix2D( ::com::sun::star::geometry::AffineMatrix2D&	matrix );
214 
215         ::com::sun::star::geometry::Matrix2D&
216         	setIdentityMatrix2D( ::com::sun::star::geometry::Matrix2D&			    matrix );
217 
218 
219         // Special utilities
220         // ===================================================================
221 
222         /** Calc the bounding rectangle of a transformed rectangle.
223 
224 			The method applies the given transformation to the
225 			specified input rectangle, and returns the bounding box of
226 			the resulting output area.
227 
228             @param o_Rect
229             Output rectangle
230 
231             @param i_Rect
232             Input rectangle
233 
234             @param i_Transformation
235             Transformation to apply to the input rectangle
236 
237             @see calcRectToRectTransform()
238 
239             @return a reference to the resulting rectangle
240          */
241         ::basegfx::B2DRange& calcTransformedRectBounds( ::basegfx::B2DRange&			o_Rect,
242                                                         const ::basegfx::B2DRange&		i_Rect,
243                                                         const ::basegfx::B2DHomMatrix&	i_Transformation );
244 
245         /** Calc a transform that maps one rectangle on top of
246             another.
247 
248         	The method is a kissing cousin to
249         	calcTransformedRectBounds(). It can be used to modify the
250         	given transformation matrix, such that it transforms the
251         	given input rectangle to the given output rectangle,
252         	changing only translation and scale (if necessary). Thus,
253         	if you've calculated an output rectangle via
254         	calcTransformedRectBounds(), you can move and scale that
255         	rectangle as you like, and have this method calculate the
256         	required total transformation for it.
257 
258             @param o_transform
259             Output parameter, to receive the resulting transformation
260             matrix.
261 
262             @param i_destRect
263             Input parameter, specifies the requested destination
264             rectangle. The resulting transformation will exactly map
265             the source rectangle to the destination rectangle.
266 
267             @param i_srcRect
268             Input parameter, specifies the original source
269             rectangle. The resulting transformation will exactly map
270             the source rectangle to the destination rectangle.
271 
272             @param i_transformation
273             The original transformation matrix. This is changed with
274             translations and scalings (if necessary), to exactly map
275             the source rectangle to the destination rectangle.
276 
277             @return a reference to the resulting transformation matrix
278 
279             @see calcTransformedRectBounds()
280         */
281         ::basegfx::B2DHomMatrix& calcRectToRectTransform( ::basegfx::B2DHomMatrix&			o_transform,
282                                                           const ::basegfx::B2DRange&		i_destRect,
283                                                           const ::basegfx::B2DRange&		i_srcRect,
284                                                           const ::basegfx::B2DHomMatrix&	i_transformation );
285 
286         /** Calc a transform that maps the upper, left corner of a
287          	rectangle to the origin.
288 
289         	The method is a specialized version of
290         	calcRectToRectTransform(), mapping the input rectangle's
291         	the upper, left corner to the origin, and leaving the size
292         	untouched.
293 
294             @param o_transform
295             Output parameter, to receive the resulting transformation
296             matrix.
297 
298             @param i_srcRect
299             Input parameter, specifies the original source
300             rectangle. The resulting transformation will exactly map
301             the source rectangle's upper, left corner to the origin.
302 
303             @param i_transformation
304             The original transformation matrix. This is changed with
305             translations (if necessary), to exactly map the source
306             rectangle to the origin.
307 
308             @return a reference to the resulting transformation matrix
309 
310             @see calcRectToRectTransform()
311             @see calcTransformedRectBounds()
312         */
313         ::basegfx::B2DHomMatrix& calcRectToOriginTransform( ::basegfx::B2DHomMatrix&		o_transform,
314                                                             const ::basegfx::B2DRange&		i_srcRect,
315                                                             const ::basegfx::B2DHomMatrix&	i_transformation );
316 
317         /** Check whether a given rectangle is within another
318             transformed rectangle.
319 
320             This method checks for polygonal containedness, i.e. the
321             transformed rectangle is not represented as an axis-alignd
322             rectangle anymore (like calcTransformedRectBounds()), but
323             polygonal. Thus, the insideness test is based on tight
324             bounds.
325 
326             @param rContainedRect
327             This rectangle is checked, whether it is fully within the
328             transformed rTransformRect.
329 
330             @param rTransformRect
331             This rectangle is transformed, and then checked whether it
332             fully contains rContainedRect.
333 
334             @param rTransformation
335             This transformation is applied to rTransformRect
336          */
337 		bool isInside( const ::basegfx::B2DRange& 		rContainedRect,
338                        const ::basegfx::B2DRange& 		rTransformRect,
339                        const ::basegfx::B2DHomMatrix&	rTransformation );
340 
341         /** Clip a scroll to the given bound rect
342 
343             @param io_rSourceArea
344             Source area to scroll. The resulting clipped source area
345             is returned therein.
346 
347             @param io_rDestPoint
348             Destination point of the scroll (upper, left corner of
349             rSourceArea after the scroll). The new, resulting
350             destination point is returned therein.q
351 
352             @param o_ClippedAreas
353             Vector of rectangles in the <em>destination</em> area
354             coordinate system, which are clipped away from the source
355             area, and thus need extra updates (i.e. they are not
356             correctly copy from the scroll operation, since there was
357             no information about them in the source).
358 
359             @param rBounds
360             Bounds to clip against.
361 
362             @return false, if the resulting scroll area is empty
363          */
364         bool clipScrollArea( ::basegfx::B2IRange&                  io_rSourceArea,
365                              ::basegfx::B2IPoint&                  io_rDestPoint,
366                              ::std::vector< ::basegfx::B2IRange >& o_ClippedAreas,
367                              const ::basegfx::B2IRange&            rBounds );
368 
369         /** Clip a blit between two differently surfaces.
370 
371             This method clips source and dest rect for a clip between
372             two differently clipped surfaces, such that the resulting
373             blit rects are fully within both clip areas.
374 
375             @param io_rSourceArea
376             Source area of the blit. Returned therein is the computed
377             clipped source area.
378 
379             @param io_rDestPoint
380             Dest area of the blit. Returned therein is the computed
381             clipped dest area.
382 
383             @param rSourceBounds
384             Clip bounds of the source surface
385 
386             @param rDestBounds
387             Clip bounds of the dest surface
388 
389             @return false, if the resulting blit is empty, i.e. fully
390             clipped away.
391          */
392         bool clipBlit( ::basegfx::B2IRange&       io_rSourceArea,
393                        ::basegfx::B2IPoint&       io_rDestPoint,
394                        const ::basegfx::B2IRange& rSourceBounds,
395                        const ::basegfx::B2IRange& rDestBounds );
396 
397         /** Return range of integer pixel, which will cover the sprite
398             given by the floating point range.
399 
400             This method assumes that sprite sizes are always integer,
401             and that the sprite position (top, left edge of the
402             sprite) is rounded to the nearest integer before
403             rendering.
404 
405 			@param rRange
406             Input range. Values must be within the representable
407             bounds of sal_Int32
408 
409             @return the integer range, which is covered by the sprite
410             given by rRange.
411          */
412         ::basegfx::B2IRange spritePixelAreaFromB2DRange( const ::basegfx::B2DRange& rRange );
413 
414         /** Retrieve various internal properties of the actual canvas implementation.
415 
416         	This method retrieves a bunch of internal, implementation-
417         	and platform-dependent values from the canvas
418         	implementation. Among them are for example operating
419         	system window handles. The actual layout and content of
420         	the returned sequence is dependent on the component
421         	implementation, undocumented and subject to change.
422 
423             @param i_rxCanvas
424             Input parameter, the canvas representation for which the device information
425 			is to be retrieveds
426 
427             @param o_rxParams
428             Output parameter, the sequence of Anys that hold the device parameters. Layout is as described above
429 
430             @return A reference to the resulting sequence of parameters
431 		*/
432 		::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& getDeviceInfo(
433 			const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas >& i_rxCanvas,
434 			::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& o_rxParams );
435 
436         /** Return a color space for a default RGBA integer format
437 
438             Use this method for dead-simple bitmap implementations,
439             that map all their formats to 8888 RGBA color.
440          */
441         ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XIntegerBitmapColorSpace> getStdColorSpace();
442 
443         /** Return a memory layout for a default RGBA integer format
444 
445             Use this method for dead-simple bitmap implementations,
446             that map all their formats to 8888 RGBA color.
447          */
448         ::com::sun::star::rendering::IntegerBitmapLayout getStdMemoryLayout(
449             const ::com::sun::star::geometry::IntegerSize2D& rBitmapSize );
450 
451         /// Convert standard 8888 RGBA color to vcl color
452         ::Color stdIntSequenceToColor( const ::com::sun::star::uno::Sequence<sal_Int8>& rColor );
453 
454         /// Convert standard 8888 RGBA color to vcl color
455         ::com::sun::star::uno::Sequence<sal_Int8> colorToStdIntSequence( const ::Color& rColor );
456 
457         // Modeled closely after boost::numeric_cast, only that we
458         // issue some trace output here and throw a RuntimeException
459 
460         /** Cast numeric value into another (numeric) data type
461 
462         	Apart from converting the numeric value, this template
463         	also checks if any overflow, underflow, or sign
464         	information is lost (if yes, it throws an
465         	uno::RuntimeException.
466          */
numeric_cast(Source arg)467         template< typename Target, typename Source > inline Target numeric_cast( Source arg )
468         {
469             // typedefs abbreviating respective trait classes
470             typedef ::std::numeric_limits< Source > SourceLimits;
471             typedef ::std::numeric_limits< Target > TargetLimits;
472 
473             if( ( arg<0 && !TargetLimits::is_signed) || 					// loosing the sign here
474                 ( SourceLimits::is_signed && arg<TargetLimits::min()) ||	// underflow will happen
475                 ( arg>TargetLimits::max() ) ) 					            // overflow will happen
476             {
477 #if defined(VERBOSE) && defined(DBG_UTIL)
478                 OSL_TRACE("numeric_cast detected data loss");
479 #endif
480                 throw ::com::sun::star::uno::RuntimeException(
481                     ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "numeric_cast detected data loss" )),
482                     NULL );
483             }
484 
485             return static_cast<Target>(arg);
486         }
487 
488         ::com::sun::star::awt::Rectangle getAbsoluteWindowRect(
489             const ::com::sun::star::awt::Rectangle&                                    rRect,
490             const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow2 >& xWin  );
491 
492         /** Retrieve for small bound marks around each corner of the given rectangle
493          */
494         ::basegfx::B2DPolyPolygon getBoundMarksPolyPolygon( const ::basegfx::B2DRange& rRange );
495 
496         /** Calculate number of gradient "strips" to generate (takes
497            into account device resolution)
498 
499            @param nColorSteps
500            Maximal integer difference between all color stops, needed
501            for smooth gradient color differences
502          */
503         int calcGradientStepCount( ::basegfx::B2DHomMatrix&                        rTotalTransform,
504                                    const ::com::sun::star::rendering::ViewState&   viewState,
505                                    const ::com::sun::star::rendering::RenderState& renderState,
506                                    const ::com::sun::star::rendering::Texture&     texture,
507                                    int                                             nColorSteps );
508 
509         /** A very simplistic map for ASCII strings and arbitrary value
510             types.
511 
512             This class internally references a constant, static array of
513             sorted MapEntries, and performs a binary search to look up
514             values for a given query string. Note that this map is static,
515             i.e. not meant to be extented at runtime.
516 
517             @tpl ValueType
518             The value type this map should store, associated with an ASCII
519             string.
520         */
521         template< typename ValueType > class ValueMap
522         {
523         public:
524             struct MapEntry
525             {
526                 const char*		maKey;
527                 ValueType		maValue;
528             };
529 
530             /** Create a ValueMap for the given array of MapEntries.
531 
532                 @param pMap
533                 Pointer to a <em>static</em> array of MapEntries. Must
534                 live longer than this object! Make absolutely sure that
535                 the string entries passed via pMap are ASCII-only -
536                 everything else might not yield correct string
537                 comparisons, and thus will result in undefined behaviour.
538 
539                 @param nEntries
540                 Number of entries for pMap
541 
542                 @param bCaseSensitive
543                 Whether the map query should be performed case sensitive
544                 or not. When bCaseSensitive is false, all MapEntry strings
545                 must be lowercase!
546             */
ValueMap(const MapEntry * pMap,::std::size_t nEntries,bool bCaseSensitive)547             ValueMap( const MapEntry* 	pMap,
548                       ::std::size_t		nEntries,
549                       bool				bCaseSensitive ) :
550                 mpMap( pMap ),
551                 mnEntries( nEntries ),
552                 mbCaseSensitive( bCaseSensitive )
553             {
554 #ifdef DBG_UTIL
555                 // Ensure that map entries are sorted (and all lowercase, if this
556                 // map is case insensitive)
557                 const ::rtl::OString aStr( pMap->maKey );
558                 if( !mbCaseSensitive &&
559                     aStr != aStr.toAsciiLowerCase() )
560                 {
561                     OSL_TRACE("ValueMap::ValueMap(): Key %s is not lowercase",
562                               pMap->maKey);
563                     OSL_ENSURE( false, "ValueMap::ValueMap(): Key is not lowercase" );
564                 }
565 
566                 if( mnEntries > 1 )
567                 {
568                     for( ::std::size_t i=0; i<mnEntries-1; ++i, ++pMap )
569                     {
570                         if( !mapComparator(pMap[0], pMap[1]) &&
571                             mapComparator(pMap[1], pMap[0]) )
572                         {
573                             OSL_TRACE("ValueMap::ValueMap(): Map is not sorted, keys %s and %s are wrong",
574                                       pMap[0].maKey,
575                                       pMap[1].maKey);
576                             OSL_ENSURE( false,
577                                         "ValueMap::ValueMap(): Map is not sorted" );
578                         }
579 
580                         const ::rtl::OString aStr2( pMap[1].maKey );
581                         if( !mbCaseSensitive &&
582                             aStr2 != aStr2.toAsciiLowerCase() )
583                         {
584                             OSL_TRACE("ValueMap::ValueMap(): Key %s is not lowercase",
585                                       pMap[1].maKey);
586                             OSL_ENSURE( false, "ValueMap::ValueMap(): Key is not lowercase" );
587                         }
588                     }
589                 }
590 #endif
591             }
592 
593             /** Lookup a value for the given query string
594 
595                 @param rName
596                 The string to lookup. If the map was created with the case
597                 insensitive flag, the lookup is performed
598                 case-insensitive, otherwise, case-sensitive.
599 
600                 @param o_rResult
601                 Output parameter, which receives the value associated with
602                 the query string. If no value was found, the referenced
603                 object is kept unmodified.
604 
605                 @return true, if a matching entry was found.
606             */
lookup(const::rtl::OUString & rName,ValueType & o_rResult) const607             bool lookup( const ::rtl::OUString& rName,
608                          ValueType&				o_rResult ) const
609             {
610                 // rName is required to contain only ASCII characters.
611                 // TODO(Q1): Enforce this at upper layers
612                 ::rtl::OString aKey( ::rtl::OUStringToOString( mbCaseSensitive ? rName : rName.toAsciiLowerCase(),
613                                                                RTL_TEXTENCODING_ASCII_US ) );
614                 MapEntry aSearchKey =
615                     {
616                         aKey.getStr(),
617                         ValueType()
618                     };
619 
620                 const MapEntry* pRes;
621                 const MapEntry* pEnd = mpMap+mnEntries;
622                 if( (pRes=::std::lower_bound( mpMap,
623                                               pEnd,
624                                               aSearchKey,
625                                               &mapComparator )) != pEnd )
626                 {
627                     // place to _insert before_ found - is it equal to
628                     // the search key?
629                     if( strcmp( pRes->maKey, aSearchKey.maKey ) == 0 )
630                     {
631                         // yep, correct entry found
632                         o_rResult = pRes->maValue;
633                         return true;
634                     }
635                 }
636 
637                 // not found
638                 return false;
639             }
640 
641         private:
mapComparator(const MapEntry & rLHS,const MapEntry & rRHS)642             static bool mapComparator( const MapEntry& rLHS,
643                                        const MapEntry& rRHS )
644             {
645                 return strcmp( rLHS.maKey,
646                                rRHS.maKey ) < 0;
647             }
648 
649             const MapEntry* 	mpMap;
650             ::std::size_t		mnEntries;
651             bool				mbCaseSensitive;
652         };
653     }
654 }
655 
656 #endif /* INCLUDED_CANVAS_CANVASTOOLS_HXX */
657 // eof
658