f673bc22006d8f7191f7cb7f417741ea2af18b7d
[platform/framework/native/uifw.git] / src / graphics / FGrp_CanvasPixman.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0/
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 /*
19  * @file                FGrp_CanvasPixman.cpp
20  * @brief               This is the implementation file for the pixman solution.
21  *
22  */
23
24 #include <memory>
25
26 #include <math.h>
27
28 #include "FGrp_CanvasPixman.h"
29 #include "util/FGrp_UtilTemplate.h"
30
31
32 namespace Tizen { namespace Graphics
33 {
34
35 namespace _Util
36 {
37
38 template <>
39 AutoDeletor<pixman_image_t>::~AutoDeletor(void)
40 {
41         if (__pPtr)
42         {
43                 pixman_image_unref(__pPtr);
44         }
45 }
46
47 } // _Util
48
49 namespace _Pixman
50 {
51
52 pixman_op_t GetRop(Tizen::Graphics::CompositeMode compositeMode)
53 {
54         switch (compositeMode)
55         {
56         case COMPOSITE_MODE_CLEAR:
57                 return PIXMAN_OP_CLEAR;
58         case COMPOSITE_MODE_SRC:
59                 return PIXMAN_OP_SRC;
60         case COMPOSITE_MODE_DST:
61                 return PIXMAN_OP_DST;
62         case COMPOSITE_MODE_SRC_OVER:
63                 return PIXMAN_OP_OVER;
64         case COMPOSITE_MODE_DST_OVER:
65                 return PIXMAN_OP_OVER_REVERSE;
66         case COMPOSITE_MODE_SRC_IN:
67                 return PIXMAN_OP_IN;
68         case COMPOSITE_MODE_DST_IN:
69                 return PIXMAN_OP_IN_REVERSE;
70         case COMPOSITE_MODE_SRC_OUT:
71                 return PIXMAN_OP_OUT;
72         case COMPOSITE_MODE_DST_OUT:
73                 return PIXMAN_OP_OUT_REVERSE;
74         case COMPOSITE_MODE_SRC_ATOP:
75                 return PIXMAN_OP_ATOP;
76         case COMPOSITE_MODE_DST_ATOP:
77                 return PIXMAN_OP_ATOP_REVERSE;
78         case COMPOSITE_MODE_DST_XOR:
79                 return PIXMAN_OP_XOR;
80         case COMPOSITE_MODE_ADD:
81                 return PIXMAN_OP_ADD;
82         case COMPOSITE_MODE_SATURATE:
83                 return PIXMAN_OP_SATURATE;
84         case COMPOSITE_MODE_MULTIPLY:
85                 return PIXMAN_OP_MULTIPLY;
86         case COMPOSITE_MODE_SCREEN:
87                 return PIXMAN_OP_SCREEN;
88         case COMPOSITE_MODE_OVERLAY:
89                 return PIXMAN_OP_OVERLAY;
90         case COMPOSITE_MODE_DARKEN:
91                 return PIXMAN_OP_DARKEN;
92         case COMPOSITE_MODE_LIGHTEN:
93                 return PIXMAN_OP_LIGHTEN;
94         default:
95                 return PIXMAN_OP_SRC;
96         }
97 }
98
99 pixman_filter_t GetFilter(BitmapDrawingQuality drawingQuality)
100 {
101         switch (drawingQuality)
102         {
103         case Tizen::Graphics::BITMAP_DRAWING_QUALITY_HIGH:
104                 return PIXMAN_FILTER_BEST;
105         case Tizen::Graphics::BITMAP_DRAWING_QUALITY_MID:
106                 return PIXMAN_FILTER_GOOD;
107         default:
108                 return PIXMAN_FILTER_FAST;
109         }
110 }
111
112 pixman_filter_t GetFilter(BitmapScalingQuality scalingQuality)
113 {
114         switch (scalingQuality)
115         {
116         case Tizen::Graphics::BITMAP_SCALING_QUALITY_HIGH:
117                 return PIXMAN_FILTER_BEST;
118         case Tizen::Graphics::BITMAP_SCALING_QUALITY_MID:
119                 return PIXMAN_FILTER_GOOD;
120         default:
121                 return PIXMAN_FILTER_FAST;
122         }
123 }
124
125 pixman_transform_t GetTransform(int xDest, int yDest, double degree, int xPivot, int yPivot)
126 {
127         pixman_transform_t transform;
128
129         double c = cos(degree * 3.141592 / 180.0);
130         double s = sin(degree * 3.141592 / 180.0);
131
132         pixman_transform_init_identity(&transform);
133
134         pixman_transform_translate(&transform, NULL, pixman_int_to_fixed(-xDest), pixman_int_to_fixed(-yDest));
135         pixman_transform_rotate(&transform, NULL, pixman_double_to_fixed(c), pixman_double_to_fixed(s));
136         pixman_transform_translate(&transform, NULL, pixman_int_to_fixed(xPivot), pixman_int_to_fixed(yPivot));
137
138         return transform;
139 }
140
141 pixman_transform_t GetTransform(double xDest, double yDest, double degree, double xPivot, double yPivot)
142 {
143         pixman_transform_t transform;
144
145         double c = cos(degree * 3.141592 / 180.0);
146         double s = sin(degree * 3.141592 / 180.0);
147
148         pixman_transform_init_identity(&transform);
149
150         pixman_transform_translate(&transform, NULL, pixman_double_to_fixed(-xDest), pixman_double_to_fixed(-yDest));
151         pixman_transform_rotate(&transform, NULL, pixman_double_to_fixed(c), pixman_double_to_fixed(s));
152         pixman_transform_translate(&transform, NULL, pixman_double_to_fixed(xPivot), pixman_double_to_fixed(yPivot));
153
154         return transform;
155 }
156
157 pixman_transform_t GetTransform(int srcWidth, int srcHeight, int dstWidth, int dstHeight)
158 {
159         pixman_transform_t transform;
160
161         pixman_transform_init_scale(&transform, 65536 * srcWidth / dstWidth,  65536 * srcHeight / dstHeight);
162
163         return transform;
164 }
165
166 pixman_transform_t GetTransform(int srcWidth, int srcHeight, double xDest, double yDest, double wDest, double hDest)
167 {
168         pixman_transform_t transform;
169
170         pixman_transform_init_identity(&transform);
171
172         pixman_transform_translate(&transform, NULL, pixman_double_to_fixed(-xDest), pixman_double_to_fixed(-yDest));
173         pixman_transform_scale(&transform, NULL, 65536 * srcWidth / wDest,  65536 * srcHeight / hDest);
174
175         return transform;
176 }
177
178 bool ResizePixmap(Tizen::Graphics::_Util::Pixmap& dstImage, const Tizen::Graphics::_Util::Pixmap& srcImage, pixman_filter_t filter)
179 {
180         Tizen::Graphics::_Util::AutoDeletor<pixman_image_t> pPixmanDst;
181
182         switch (dstImage.depth)
183         {
184         case 16:
185                 pPixmanDst.Bind(pixman_image_create_bits(PIXMAN_r5g6b5, dstImage.width, dstImage.height, (uint32_t*)dstImage.pBitmap, dstImage.bytesPerLine));
186                 break;
187         case 32:
188                 pPixmanDst.Bind(pixman_image_create_bits(PIXMAN_a8r8g8b8, dstImage.width, dstImage.height, (uint32_t*)dstImage.pBitmap, dstImage.bytesPerLine));
189                 break;
190         default:
191                 return false;
192         }
193
194         if (pPixmanDst)
195         {
196                 Tizen::Graphics::_Util::AutoDeletor<pixman_image_t> pPixmanSrc;
197
198                 switch (srcImage.depth)
199                 {
200                 case 16:
201                         // color key is not supporting
202                         pPixmanSrc.Bind(pixman_image_create_bits(PIXMAN_r5g6b5, srcImage.width, srcImage.height, (uint32_t*)srcImage.pBitmap, srcImage.bytesPerLine));
203                         break;
204                 case 32:
205                         pPixmanSrc.Bind(pixman_image_create_bits(PIXMAN_a8r8g8b8, srcImage.width, srcImage.height, (uint32_t*)srcImage.pBitmap, srcImage.bytesPerLine));
206                         break;
207                 default:
208                         return false;
209                 }
210
211                 if (pPixmanSrc)
212                 {
213                         pixman_transform_t transform = Tizen::Graphics::_Pixman::GetTransform(srcImage.width, srcImage.height, dstImage.width, dstImage.height);
214
215                         pixman_image_set_transform(pPixmanSrc, &transform);
216
217                         pixman_image_set_filter(pPixmanSrc, filter, NULL, 0);
218
219                         pixman_image_set_repeat(pPixmanSrc, PIXMAN_REPEAT_REFLECT);
220
221                         pixman_image_composite32(PIXMAN_OP_SRC, pPixmanSrc, 0, pPixmanDst, 0, 0, 0, 0, 0, 0, dstImage.width, dstImage.height);
222
223                         return true;
224                 }
225         }
226
227         return false;
228 }
229
230 bool CompositePixmap(Tizen::Graphics::_Util::Pixmap& dstImage, const Tizen::Graphics::_Util::Pixmap& srcImage, int rop, pixman_filter_t filter, pixman_transform_t transform, pixman_repeat_t repeatMethod)
231 {
232         Tizen::Graphics::_Util::AutoDeletor<pixman_image_t> pPixmanDst;
233
234         switch (dstImage.depth)
235         {
236         case 16:
237                 pPixmanDst.Bind(pixman_image_create_bits(PIXMAN_r5g6b5, dstImage.width, dstImage.height, (uint32_t*)dstImage.pBitmap, dstImage.bytesPerLine));
238                 break;
239         case 32:
240                 pPixmanDst.Bind(pixman_image_create_bits(PIXMAN_a8r8g8b8, dstImage.width, dstImage.height, (uint32_t*)dstImage.pBitmap, dstImage.bytesPerLine));
241                 break;
242         default:
243                 return false;
244         }
245
246         if (pPixmanDst)
247         {
248                 std::auto_ptr<Tizen::Graphics::_Util::Pixmap> premultipliedSrcImage;
249
250                 Tizen::Graphics::_Util::AutoDeletor<pixman_image_t> pPixmanMsk;
251                 Tizen::Graphics::_Util::AutoDeletor<pixman_image_t> pPixmanSrc;
252
253                 switch (srcImage.depth)
254                 {
255                 case 16:
256                         // color key is not supporting
257                         pPixmanSrc.Bind(pixman_image_create_bits(PIXMAN_r5g6b5, srcImage.width, srcImage.height, (uint32_t*)srcImage.pBitmap, srcImage.bytesPerLine));
258                         break;
259                 case 32:
260                         if (srcImage.isPremultiplied || rop == PIXMAN_OP_COPY)
261                         {
262                                 pPixmanSrc.Bind(pixman_image_create_bits(PIXMAN_a8r8g8b8, srcImage.width, srcImage.height, (uint32_t*)srcImage.pBitmap, srcImage.bytesPerLine));
263                         }
264                         else
265                         {
266                                 bool pass = false;
267                                 bool isInternalSolutionEnable = !((dstImage.width == srcImage.width) && (dstImage.height == srcImage.height) && pixman_transform_is_identity(&transform));
268
269                                 if (isInternalSolutionEnable)
270                                 {
271                                         premultipliedSrcImage.reset(srcImage.GetPremultipliedPixmap());
272
273                                         if (premultipliedSrcImage.get())
274                                         {
275                                                 pPixmanSrc.Bind(pixman_image_create_bits(PIXMAN_a8r8g8b8, premultipliedSrcImage->width, premultipliedSrcImage->height, (uint32_t*)premultipliedSrcImage->pBitmap, premultipliedSrcImage->bytesPerLine));
276                                                 pass = true;
277                                         }
278                                 }
279
280                                 if (!pass)
281                                 {
282                                         // slow but it does not create additional buffer
283                                         pPixmanSrc.Bind(pixman_image_create_bits(PIXMAN_x8r8g8b8, srcImage.width, srcImage.height, (uint32_t*)srcImage.pBitmap, srcImage.bytesPerLine));
284                                         pPixmanMsk.Bind(pixman_image_create_bits(PIXMAN_a8r8g8b8, srcImage.width, srcImage.height, (uint32_t*)srcImage.pBitmap, srcImage.bytesPerLine));
285
286                                         if (pPixmanMsk == null)
287                                         {
288                                                 return false;
289                                         }
290                                 }
291                         }
292                         break;
293                 default:
294                         return false;
295                 }
296
297                 if (pPixmanSrc)
298                 {
299                         pixman_image_set_transform(pPixmanSrc, &transform);
300
301                         if (pPixmanMsk)
302                         {
303                                 pixman_image_set_transform(pPixmanMsk, &transform);
304                         }
305
306                         pixman_image_set_filter(pPixmanSrc, filter, NULL, 0);
307                         pixman_image_set_repeat(pPixmanSrc, repeatMethod);
308
309                         if (rop == PIXMAN_OP_COPY)
310                         {
311                                 rop = PIXMAN_OP_SRC;
312                         }
313
314                         pixman_image_composite32(pixman_op_t(rop), pPixmanSrc, pPixmanMsk, pPixmanDst, 0, 0, 0, 0, 0, 0, dstImage.width, dstImage.height);
315
316                         return true;
317                 }
318         }
319
320         return false;
321 }
322
323 bool ResizePixmap(Tizen::Graphics::_Util::Pixmap& dstImage, const Tizen::Graphics::_Util::Pixmap& srcImage, Tizen::Graphics::BitmapScalingQuality scalingQuality)
324 {
325         if (dstImage.width <= 0 || dstImage.height <= 0)
326         {
327                 return true;
328         }
329
330         pixman_filter_t filter = Tizen::Graphics::_Pixman::GetFilter(scalingQuality);
331
332         return ResizePixmap(dstImage, srcImage, filter);
333 }
334
335 bool CopyPixmap(Tizen::Graphics::_Util::Pixmap& dstImage, const Tizen::Graphics::_Util::Pixmap& srcImage, Tizen::Graphics::BitmapDrawingQuality drawingQuality, Tizen::Graphics::CompositeMode compositeMode)
336 {
337         if (dstImage.width <= 0 || dstImage.height <= 0)
338         {
339                 return true;
340         }
341
342         pixman_op_t rop = Tizen::Graphics::_Pixman::GetRop(compositeMode);
343
344         pixman_filter_t filter = Tizen::Graphics::_Pixman::GetFilter(drawingQuality);
345
346         pixman_transform_t transform;
347         pixman_transform_init_identity(&transform);
348
349         return CompositePixmap(dstImage, srcImage, rop, filter, transform, PIXMAN_REPEAT_NONE);
350 }
351
352 bool CopyPixmap(Tizen::Graphics::_Util::Pixmap& dstImage, const Tizen::Graphics::_Util::Pixmap& srcImage, Tizen::Graphics::BitmapDrawingQuality drawingQuality, Tizen::Graphics::CompositeMode compositeMode, double xDest, double yDest)
353 {
354         if (dstImage.width <= 0 || dstImage.height <= 0)
355         {
356                 return true;
357         }
358
359         pixman_op_t rop = Tizen::Graphics::_Pixman::GetRop(compositeMode);
360
361         pixman_filter_t filter = Tizen::Graphics::_Pixman::GetFilter(drawingQuality);
362
363         switch (rop)
364         {
365         case PIXMAN_OP_IN:
366         case PIXMAN_OP_IN_REVERSE:
367         case PIXMAN_OP_OUT:
368         case PIXMAN_OP_ATOP_REVERSE:
369                 {
370                         pixman_transform_t transform;
371                         pixman_transform_init_identity(&transform);
372                         pixman_transform_translate(&transform, NULL, pixman_double_to_fixed(-(xDest - 0.5)), pixman_double_to_fixed(-(yDest - 0.5)));
373
374                         return CompositePixmap(dstImage, srcImage, rop, filter, transform, PIXMAN_REPEAT_NONE);
375                 }
376         default:
377                 {
378                         int dstX1 = int(floor(xDest));
379                         int dstX2 = int(ceil(xDest + srcImage.width));
380                         int dstY1 = int(floor(yDest));
381                         int dstY2 = int(ceil(yDest + srcImage.height));
382
383                         Tizen::Graphics::_Util::Pixmap dstImageSub = dstImage.GetSubBitmap(dstX1, dstY1, dstX2 - dstX1, dstY2 - dstY1);
384                         Tizen::Graphics::_Util::Pixmap srcImageSub = srcImage.GetSubBitmap((dstX1 >= 0) ? 0 : -dstX1, (dstY1 >= 0) ? 0 : -dstY1, srcImage.width, srcImage.height);
385
386                         pixman_transform_t transform;
387                         pixman_transform_init_identity(&transform);
388                         pixman_transform_translate(&transform, NULL, pixman_double_to_fixed(dstX1 -(xDest - 0.5)), pixman_double_to_fixed(dstY1 -(yDest - 0.5)));
389                         return CompositePixmap(dstImageSub, srcImageSub, rop, filter, transform, PIXMAN_REPEAT_NONE);
390                 }
391         }
392 }
393
394 bool ScalePixmap(Tizen::Graphics::_Util::Pixmap& dstImage, const Tizen::Graphics::_Util::Pixmap& srcImage, Tizen::Graphics::BitmapDrawingQuality drawingQuality, Tizen::Graphics::CompositeMode compositeMode)
395 {
396         if (dstImage.width <= 0 || dstImage.height <= 0)
397         {
398                 return true;
399         }
400
401         if (dstImage.width == srcImage.width && dstImage.height == srcImage.height)
402         {
403                 return CopyPixmap(dstImage, srcImage, drawingQuality, compositeMode);
404         }
405
406         pixman_op_t rop = Tizen::Graphics::_Pixman::GetRop(compositeMode);
407         pixman_filter_t filter = Tizen::Graphics::_Pixman::GetFilter(drawingQuality);
408         pixman_transform_t transform = Tizen::Graphics::_Pixman::GetTransform(srcImage.width, srcImage.height, dstImage.width, dstImage.height);
409
410         return CompositePixmap(dstImage, srcImage, rop, filter, transform, PIXMAN_REPEAT_NORMAL);
411 }
412
413 bool ScalePixmapOpCopy(Tizen::Graphics::_Util::Pixmap& dstImage, const Tizen::Graphics::_Util::Pixmap& srcImage, Tizen::Graphics::BitmapDrawingQuality drawingQuality)
414 {
415         if (dstImage.width <= 0 || dstImage.height <= 0)
416         {
417                 return true;
418         }
419
420         pixman_filter_t filter = Tizen::Graphics::_Pixman::GetFilter(drawingQuality);
421         pixman_transform_t transform = Tizen::Graphics::_Pixman::GetTransform(srcImage.width, srcImage.height, dstImage.width, dstImage.height);
422
423         return CompositePixmap(dstImage, srcImage, PIXMAN_OP_COPY, filter, transform, PIXMAN_REPEAT_NORMAL);
424 }
425
426 bool ScalePixmap(Tizen::Graphics::_Util::Pixmap& dstImage, const Tizen::Graphics::_Util::Pixmap& srcImage, Tizen::Graphics::BitmapDrawingQuality drawingQuality, Tizen::Graphics::CompositeMode compositeMode, double xDest, double yDest, double wDest, double hDest)
427 {
428         if (dstImage.width <= 0 || dstImage.height <= 0)
429         {
430                 return true;
431         }
432
433         pixman_op_t rop = Tizen::Graphics::_Pixman::GetRop(compositeMode);
434         pixman_filter_t filter = Tizen::Graphics::_Pixman::GetFilter(drawingQuality);
435
436         switch (rop)
437         {
438         case PIXMAN_OP_IN:
439         case PIXMAN_OP_IN_REVERSE:
440         case PIXMAN_OP_OUT:
441         case PIXMAN_OP_ATOP_REVERSE:
442                 {
443                         pixman_transform_t transform = Tizen::Graphics::_Pixman::GetTransform(srcImage.width, srcImage.height, xDest - 0.5, yDest - 0.5, wDest, hDest);
444
445                         return CompositePixmap(dstImage, srcImage, rop, filter, transform, PIXMAN_REPEAT_NONE);
446                 }
447         default:
448                 {
449                         int dstX1 = int(floor(xDest));
450                         int dstY1 = int(floor(yDest));
451                         int dstX2 = int(ceil(xDest + wDest));
452                         int dstY2 = int(ceil(yDest + hDest));
453
454                         Tizen::Graphics::_Util::Pixmap dstImageSub = dstImage.GetSubBitmap(dstX1, dstY1, dstX2 - dstX1, dstY2 - dstY1);
455                         Tizen::Graphics::_Util::Pixmap srcImageSub = srcImage.GetSubBitmap((dstX1 >= 0) ? 0 : int(-dstX1 * srcImage.width / wDest), (dstY1 >= 0) ? 0 : int(-dstY1 * srcImage.height / hDest), srcImage.width, srcImage.height);
456
457                         pixman_transform_t transform = Tizen::Graphics::_Pixman::GetTransform(srcImage.width, srcImage.height, (xDest - 0.5) - dstX1, (yDest - 0.5) - dstY1, wDest, hDest);
458
459                         return CompositePixmap(dstImageSub, srcImageSub, rop, filter, transform, PIXMAN_REPEAT_NONE);
460                 }
461         }
462 }
463
464 bool RotatePixmap(Tizen::Graphics::_Util::Pixmap& dstImage, const Tizen::Graphics::_Util::Pixmap& srcImage, Tizen::Graphics::BitmapDrawingQuality drawingQuality, Tizen::Graphics::CompositeMode compositeMode, double xDest, double yDest, double degree, double xPivot, double yPivot)
465 {
466         if (dstImage.width <= 0 || dstImage.height <= 0)
467         {
468                 return true;
469         }
470
471         pixman_op_t rop = Tizen::Graphics::_Pixman::GetRop(compositeMode);
472         pixman_filter_t filter = Tizen::Graphics::_Pixman::GetFilter(drawingQuality);
473         pixman_transform_t transform = Tizen::Graphics::_Pixman::GetTransform(xDest, yDest, degree, xPivot, yPivot);
474
475         return CompositePixmap(dstImage, srcImage, rop, filter, transform, PIXMAN_REPEAT_NONE);
476 }
477
478 } // _Pixman
479
480 }} // Tizen::Graphics