Tizen 2.1 base
[framework/osp/uifw.git] / src / graphics / util / FGrp_Util.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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_Util.cpp
20  * @brief       This is the implementation file for internal util class.
21  *
22  */
23
24 #include <unique_ptr.h>
25
26 #include <FBaseSysLog.h>
27
28 #include "FGrp_BitmapImpl.h"
29 #include "../FGrp_Canvas.h"
30 #include "../FGrp_Bitmap.h"
31 #include "FGrp_Util.h"
32 #include "../effect/FGrp_Effect.h"
33
34
35 using namespace Tizen::Base;
36
37 namespace Tizen { namespace Graphics
38 {
39
40 namespace _Util
41 {
42
43 template <typename T>
44 bool
45 IntersectGeneralRect(Rectangle<T>& outRect, const Rectangle<T>& srcRect1, const Rectangle<T>& srcRect2)
46 {
47         typedef T Type;
48
49         struct TBound
50         {
51                 Type x1, y1, x2, y2;
52                 TBound(const Rectangle<T>& rect)
53                         : x1(rect.x)
54                         , y1(rect.y)
55                         , x2(rect.x + rect.w)
56                         , y2(rect.y + rect.h) {}
57         };
58
59         TBound srcBound1(srcRect1);
60         TBound srcBound2(srcRect2);
61
62         if (((srcRect1.w > 0 && srcRect1.h > 0) && (srcRect2.w > 0 && srcRect2.h > 0))
63                 && ((srcBound2.x2 > srcBound1.x1) && (srcBound2.x1 < srcBound1.x2) && (srcBound2.y2 > srcBound1.y1) &&
64                         (srcBound2.y1 < srcBound1.y2)))
65         {
66                 outRect.x = (srcBound2.x1 <= srcBound1.x1) ? srcBound1.x1 : srcBound2.x1;
67                 outRect.y = (srcBound2.y1 <= srcBound1.y1) ? srcBound1.y1 : srcBound2.y1;
68                 outRect.w = ((srcBound2.x2 >= srcBound1.x2) ? srcBound1.x2 : srcBound2.x2) - outRect.x;
69                 outRect.h = ((srcBound2.y2 >= srcBound1.y2) ? srcBound1.y2 : srcBound2.y2) - outRect.y;
70
71                 return true;
72         }
73         else
74         {
75                 outRect.x = 0;
76                 outRect.y = 0;
77                 outRect.w = 0;
78                 outRect.h = 0;
79
80                 return false;
81         }
82 }
83
84 } // _Util
85
86 result
87 _Util::Validate(const ::Tizen::Graphics::Rectangle& rtSrc, const ::Tizen::Graphics::Rectangle& rtDest)
88 {
89         // check 1. is width/height less or equal than 0?
90         if (rtSrc.width <= 0 || rtSrc.height <= 0 || rtDest.width <= 0 || rtDest.height <= 0)
91         {
92                 SysTryReturnResult(NID_GRP, 0, E_OUT_OF_RANGE, "The argument is out of range. (src(w:%d,h:%d), dst(w:%d,h:%d)).\n",
93                                                   rtSrc.width, rtSrc.height, rtDest.width,
94                                                   rtDest.height);
95         }
96
97         // check 2.     is src exiting outside of dest entirely?
98         if (rtSrc.x > rtDest.x + rtDest.width - 1 ||
99                 rtSrc.x + rtSrc.width - 1 < rtDest.x)
100         {
101                 SysTryReturnResult(NID_GRP, 0, E_OUT_OF_RANGE,
102                                                   "The argument is out of range. (src(x:%d,y:%d,w:%d,h:%d), dst(x:%d,y:%d,w:%d,h:%d)).\n",
103                                                   rtSrc.x,
104                                                   rtSrc.y, rtSrc.width, rtSrc.height, rtDest.x, rtDest.y, rtDest.width,
105                                                   rtDest.height);
106         }
107
108         if (rtSrc.y > rtDest.y + rtDest.height - 1 ||
109                 rtSrc.y + rtSrc.height - 1 < rtDest.y)
110         {
111                 SysTryReturnResult(NID_GRP, 0, E_OUT_OF_RANGE,
112                                                   "The argument is out of range. (src(x:%d,y:%d,w:%d,h:%d), dst(x:%d,y:%d,w:%d,h:%d)).\n",
113                                                   rtSrc.x,
114                                                   rtSrc.y, rtSrc.width, rtSrc.height, rtDest.x, rtDest.y, rtDest.width,
115                                                   rtDest.height);
116         }
117
118         return E_SUCCESS;
119 }
120
121 result
122 _Util::Validate(const ::Tizen::Graphics::Point& ptSrc, const ::Tizen::Graphics::Rectangle& rtDest)
123 {
124         SysTryReturnResult(NID_GRP, rtDest.x <= ptSrc.x &&
125                                           ptSrc.x < rtDest.x + rtDest.width &&
126                                           rtDest.y <= ptSrc.y &&
127                                           ptSrc.y < rtDest.y + rtDest.height,
128                                           E_OUT_OF_RANGE, "The argument is out of range. (src(x:%d,y:%d), dst(x:%d,y:%d,w:%d,h:%d)).\n",
129                                           ptSrc.x, ptSrc.y, rtDest.x, rtDest.y, rtDest.width,
130                                           rtDest.height);
131
132         return E_SUCCESS;
133 }
134
135 bool
136 _Util::IntersectRect(Rectangle<float>& outRect, const Rectangle<float>& srcRect1, const Rectangle<float>& srcRect2)
137 {
138         return _Util::IntersectGeneralRect<float>(outRect, srcRect1, srcRect2);
139 }
140
141 bool
142 _Util::IntersectRect(Rectangle<int>& outRect, const Rectangle<int>& srcRect1, const Rectangle<int>& srcRect2)
143 {
144         return _Util::IntersectGeneralRect<int>(outRect, srcRect1, srcRect2);
145 }
146
147 ////////////////////////////////////////////////////////////////////////////////
148 // LockManager class
149
150 _Util::LockManager::LockManager(const _Bitmap& bitmap)
151         : __pBitmap(const_cast <_Bitmap*>(&bitmap))
152         , __pCanvas(null)
153         , __pBitmapImpl(null)
154         , __pCanvasImpl(null)
155 {
156         if ((__result = __pBitmap->Lock(__bufferInfo)) != E_SUCCESS)
157         {
158                 __pBitmap = null;
159         }
160 }
161
162 _Util::LockManager::LockManager(const _Canvas& canvas)
163         : __pBitmap(null)
164         , __pCanvas(const_cast <_Canvas*>(&canvas))
165         , __pBitmapImpl(null)
166         , __pCanvasImpl(null)
167 {
168         if ((__result = __pCanvas->Lock(__bufferInfo)) != E_SUCCESS)
169         {
170                 __pCanvas = null;
171         }
172 }
173
174 _Util::LockManager::LockManager(const class _BitmapImpl& bitmapImpl)
175         : __pBitmap(null)
176         , __pCanvas(null)
177         , __pBitmapImpl(const_cast <_BitmapImpl*>(&bitmapImpl))
178         , __pCanvasImpl(null)
179 {
180         if ((__result = __pBitmapImpl->Lock(__bufferInfo)) != E_SUCCESS)
181         {
182                 __pBitmapImpl = null;
183         }
184 }
185
186 _Util::LockManager::LockManager(const class _CanvasImpl& canvasImpl)
187         : __pBitmap(null)
188         , __pCanvas(null)
189         , __pBitmapImpl(null)
190         , __pCanvasImpl(const_cast <_CanvasImpl*>(&canvasImpl))
191 {
192         if ((__result = __pCanvasImpl->Lock(__bufferInfo)) != E_SUCCESS)
193         {
194                 __pCanvasImpl = null;
195         }
196 }
197
198 _Util::LockManager::~LockManager()
199 {
200         if (__pBitmapImpl)
201         {
202                 __pBitmapImpl->Unlock();
203         }
204
205         if (__pCanvasImpl)
206         {
207                 __pCanvasImpl->Unlock();
208         }
209
210         if (__pBitmap)
211         {
212                 __pBitmap->Unlock();
213         }
214
215         if (__pCanvas)
216         {
217                 __pCanvas->Unlock();
218         }
219 }
220
221 bool
222 _Util::LockManager::IsValid(void) const
223 {
224         return (__pBitmap || __pCanvas || __pBitmapImpl || __pCanvasImpl);
225 }
226
227 result
228 _Util::LockManager::GetResult(void) const
229 {
230         return __result;
231 }
232
233 const BufferInfo&
234 _Util::LockManager::GetBufferInfo(void) const
235 {
236         return __bufferInfo;
237 }
238
239 ////////////////////////////////////////////////////////////////////////////////
240 // GetPatchList() function
241
242 namespace // unnamed
243 {
244
245 template<typename Pixel>
246 struct _NinePatchedKey
247 {
248 };
249
250 template<>
251 struct _NinePatchedKey <unsigned long>
252 {
253         enum
254         {
255                 KEY = 0xFF000000
256         };
257 };
258
259 template<>
260 struct _NinePatchedKey <unsigned short>
261 {
262         enum
263         {
264                 KEY = 0x0000
265         };
266 };
267
268 template<typename Pixel>
269 int
270 _FindWidthOfSubregions(const _Util::Pixmap& dstImage, int pRegionWidthes[], bool pWidthStretchable[])
271 {
272         enum
273         {
274                 KEY = _NinePatchedKey <Pixel>::KEY
275         };
276
277         if (dstImage.depth != sizeof(Pixel) * 8)
278         {
279                 return 0;
280         }
281
282         // find a set of width
283         int index = 0;
284         Pixel* pProbe = (Pixel*) (dstImage.pBitmap) + 1;
285         Pixel* pProbeNext = pProbe + 1;
286         Pixel* pProbeEnd = pProbe + dstImage.width - 1;
287
288         while (pProbeNext < pProbeEnd)
289         {
290                 pRegionWidthes[index]++;
291
292                 if (((*pProbe == KEY) && (*pProbeNext != KEY)) || ((*pProbe != KEY) && (*pProbeNext == KEY)))
293                 {
294                         pWidthStretchable[index] = (*pProbe == KEY) ? true : false;
295                         index++;
296                 }
297
298                 pProbe++;
299                 pProbeNext++;
300         }
301 //              pRegionWidthes[index]++;
302
303         return (index + 1);
304 }
305
306 template<typename Pixel>
307 int
308 _FindHeightOfSubregions(const _Util::Pixmap& dstImage, int pRegionHeights[], bool pHeightStretchable[])
309 {
310         enum
311         {
312                 KEY = _NinePatchedKey <Pixel>::KEY
313         };
314
315         if (dstImage.depth != sizeof(Pixel) * 8)
316         {
317                 return 0;
318         }
319
320         // find a set of height
321         int index = 0;
322         int pitch = dstImage.bytesPerLine / (dstImage.depth / 8);
323         Pixel* pProbe = (Pixel*) (dstImage.pBitmap) + pitch;
324         Pixel* pProbeNext = pProbe + pitch;
325         Pixel* pProbeEnd = pProbe + (dstImage.height - 1) * pitch;
326
327         while (pProbeNext < pProbeEnd)
328         {
329                 pRegionHeights[index]++;
330
331                 if (((*pProbe == KEY) && (*pProbeNext != KEY)) || ((*pProbe != KEY) && (*pProbeNext == KEY)))
332                 {
333                         pHeightStretchable[index] = (*pProbe == KEY) ? true : false;
334                         index++;
335                 }
336
337                 pProbe += pitch;
338                 pProbeNext += pitch;
339         }
340 //              pRegionHeights[index]++;
341
342         return (index + 1);
343 }
344
345 }
346
347 result
348 _Util::GetPatchList(_Util::AccumList <_Util::Pair <_Util::Rectangle<int>, _Util::Rectangle<int> > >& outList, const ::Tizen::Graphics::Rectangle& rect, const _Bitmap& bitmap)
349 {
350         // 1. Find withes and heights of stretchable/unstretchable regions.
351         _Util::LockManager srcLock(bitmap);
352         SysTryReturnResult(NID_GRP, srcLock.IsValid(), E_OPERATION_FAILED, "The source bitmap cannot be locked.\n");
353
354         const BufferInfo& srcBufferInfo = srcLock.GetBufferInfo();
355         _Util::Pixmap srcImage(srcBufferInfo.width, srcBufferInfo.height, srcBufferInfo.bitsPerPixel, srcBufferInfo.pPixels,
356                                                    srcBufferInfo.pitch);
357         // APPLY_SRC_BITMAP_ATTRIB(srcImage, bitmap);
358
359         std::unique_ptr<int[]> pRegionWidthes(new (std::nothrow) int[srcImage.width]);
360         SysTryReturnResult(NID_GRP, pRegionWidthes, E_OUT_OF_MEMORY, "Fails to allocate memory.\n");
361
362         std::unique_ptr<bool[]> pWidthStretchable(new (std::nothrow) bool[srcImage.width]);
363         SysTryReturnResult(NID_GRP, pWidthStretchable, E_OUT_OF_MEMORY, "Fails to allocate memory.\n");
364
365         memset(pRegionWidthes.get(), 0, sizeof(int) * srcImage.width);
366         memset(pWidthStretchable.get(), 0, sizeof(bool) * srcImage.width);
367
368         std::unique_ptr<int[]> pRegionHeights(new (std::nothrow) int[srcImage.height]);
369         SysTryReturnResult(NID_GRP, pRegionHeights, E_OUT_OF_MEMORY, "Fails to allocate memory.\n");
370
371         std::unique_ptr<bool[]> pHeightStretchable(new (std::nothrow) bool[srcImage.height]);
372         SysTryReturnResult(NID_GRP, pHeightStretchable, E_OUT_OF_MEMORY, "Fails to allocate memory.\n");
373
374         memset(pRegionHeights.get(), 0, sizeof(int) * srcImage.height);
375         memset(pHeightStretchable.get(), 0, sizeof(bool) * srcImage.height);
376
377         int numWidth = 0;
378         int numHeight = 0;
379
380         switch (srcImage.depth)
381         {
382         case 32:
383                 numWidth = _FindWidthOfSubregions <unsigned long>(srcImage, pRegionWidthes.get(), pWidthStretchable.get());
384                 numHeight = _FindHeightOfSubregions <unsigned long>(srcImage, pRegionHeights.get(), pHeightStretchable.get());
385                 break;
386
387         case 16:
388                 numWidth = _FindWidthOfSubregions <unsigned short>(srcImage, pRegionWidthes.get(), pWidthStretchable.get());
389                 numHeight = _FindHeightOfSubregions <unsigned short>(srcImage, pRegionHeights.get(), pHeightStretchable.get());
390                 break;
391         }
392         SysTryReturnResult(NID_GRP, numWidth > 0 && numHeight > 0, E_OPERATION_FAILED,
393                                           "The source bitmap is not allowable for NintPatchedBitmap.\n");
394
395         // 2. Split source image into separate stretchable/unstretchable regions.
396         std::unique_ptr< ::Tizen::Graphics::Rectangle[]> pSrcRectLists(new (std::nothrow) ::Tizen::Graphics::Rectangle[numWidth * numHeight]);
397         SysTryReturnResult(NID_GRP, pSrcRectLists, E_OUT_OF_MEMORY, "Fails to allocate memory.\n");
398
399         int vertical = 0;
400         int horizontal = 0;
401         int index = 0;
402
403         for (horizontal = 0; horizontal < numHeight; horizontal++)
404         {
405                 pSrcRectLists[index].x = 1;
406                 pSrcRectLists[index].y =
407                         (horizontal == 0) ? 1 : pSrcRectLists[index - numWidth].y + pSrcRectLists[index - numWidth].height;
408                 pSrcRectLists[index].width = pRegionWidthes[0];
409                 pSrcRectLists[index].height = pRegionHeights[horizontal];
410                 index++;
411
412                 for (vertical = 1; vertical < numWidth; vertical++)
413                 {
414                         pSrcRectLists[index].x = pSrcRectLists[index - 1].x + pSrcRectLists[index - 1].width;
415                         pSrcRectLists[index].y = pSrcRectLists[index - 1].y;
416                         pSrcRectLists[index].width = pRegionWidthes[vertical];
417                         pSrcRectLists[index].height = pSrcRectLists[index - 1].height;
418                         index++;
419                 }
420         }
421
422         // 3. Calculate stretchable/unstretchable regions of the target size.
423         int sumWidthSrcStretchableRegions = 0;
424         int sumHeightSrcStretchableRegions = 0;
425
426         for (vertical = 0; vertical < numWidth; vertical++)
427         {
428                 if (pWidthStretchable[vertical])
429                 {
430                         sumWidthSrcStretchableRegions += pRegionWidthes[vertical];
431                 }
432         }
433
434         for (horizontal = 0; horizontal < numHeight; horizontal++)
435         {
436                 if (pHeightStretchable[horizontal])
437                 {
438                         sumHeightSrcStretchableRegions += pRegionHeights[horizontal];
439                 }
440         }
441
442         int sumWidthDstStretchableRegions = rect.width - ((srcImage.width - 2) - sumWidthSrcStretchableRegions);
443         int sumHeightDstStretchableRegions = rect.height - ((srcImage.height - 2) - sumHeightSrcStretchableRegions);
444
445         for (vertical = 0; vertical < numWidth; vertical++)
446         {
447                 if (pWidthStretchable[vertical])
448                 {
449                         pRegionWidthes[vertical] =
450                                 int(float(sumWidthDstStretchableRegions) * float(pRegionWidthes[vertical]) /
451                                         float(sumWidthSrcStretchableRegions) + 0.5f);
452                 }
453         }
454
455         for (horizontal = 0; horizontal < numHeight; horizontal++)
456         {
457                 if (pHeightStretchable[horizontal])
458                 {
459                         pRegionHeights[horizontal] =
460                                 int(float(sumHeightDstStretchableRegions) * float(pRegionHeights[horizontal]) /
461                                         float(sumHeightSrcStretchableRegions) + 0.5f);
462                 }
463         }
464
465         std::unique_ptr< ::Tizen::Graphics::Rectangle[]> pDstRectLists(new (std::nothrow) ::Tizen::Graphics::Rectangle[numWidth * numHeight]);
466         SysTryReturnResult(NID_GRP, pDstRectLists, E_OUT_OF_MEMORY, "Fails to allocate memory.\n");
467
468         index = 0;
469
470         for (horizontal = 0; horizontal < numHeight; horizontal++)
471         {
472                 pDstRectLists[index].x = rect.x;
473                 pDstRectLists[index].y = (horizontal == 0) ? rect.y : pDstRectLists[index - numWidth].y + pDstRectLists[index - numWidth].height;
474                 pDstRectLists[index].width = pRegionWidthes[0];
475                 pDstRectLists[index].height = pRegionHeights[horizontal];
476                 index++;
477
478                 for (vertical = 1; vertical < numWidth; vertical++)
479                 {
480                         pDstRectLists[index].x = pDstRectLists[index - 1].x + pDstRectLists[index - 1].width;
481                         pDstRectLists[index].y = pDstRectLists[index - 1].y;
482                         pDstRectLists[index].width = pRegionWidthes[vertical];
483                         pDstRectLists[index].height = pDstRectLists[index - 1].height;
484                         index++;
485                 }
486         }
487
488         // 4. Record stretchable/unstretchable regions of bitmap to list.
489         outList.Clear();
490
491         for (index = 0; index < numWidth * numHeight; index++)
492         {
493                 _Util::Rectangle<int> destRect =
494                 {
495                         pDstRectLists[index].x,
496                         pDstRectLists[index].y,
497                         pDstRectLists[index].width,
498                         pDstRectLists[index].height
499                 };
500
501                 _Util::Rectangle<int> sourRect =
502                 {
503                         pSrcRectLists[index].x,
504                         pSrcRectLists[index].y,
505                         pSrcRectLists[index].width,
506                         pSrcRectLists[index].height
507                 };
508
509                 outList.Push(_Util::MakePair(destRect, sourRect));
510         }
511
512         return E_SUCCESS;
513 }
514
515 }} // Tizen::Graphics