Tizen 2.1 base
[framework/osp/uifw.git] / src / app / FApp_AppResourceBitmapUtil.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        FApp_AppResourceBitmapUtil.cpp
20  * @brief       This is the implementation for the _AppResourceBitmapUtil class.
21  */
22
23 #include <unique_ptr.h>
24
25 #include <FAppPkgPackageManager.h>
26 #include <FAppPkgPackageInfo.h>
27 #include <FBaseSysLog.h>
28 #include <FBaseByteBuffer.h>
29 #include <FMediaImageTypes.h>
30 #include <FMedia_ImageDecoder.h>
31 #include <FSys_SystemInfoImpl.h>
32 #include <FUi_ControlManager.h>
33 #include "FAppPkg_PackageInfoImpl.h"
34 #include "FApp_AppInfo.h"
35 #include "FApp_AppResourceBitmapUtil.h"
36
37 using namespace std;
38 using namespace Tizen::App::Package;
39 using namespace Tizen::Base;
40 using namespace Tizen::Graphics;
41 using namespace Tizen::Io;
42 using namespace Tizen::Media;
43 using namespace Tizen::Ui;
44
45 namespace // unnamed
46 {
47 MediaPixelFormat
48 ConvertBitmapPixelFormatToMediaPixelFormat(BitmapPixelFormat format)
49 {
50         MediaPixelFormat out = MEDIA_PIXEL_FORMAT_NONE;
51         switch (format)
52         {
53         case BITMAP_PIXEL_FORMAT_RGB565:
54                 out = MEDIA_PIXEL_FORMAT_RGB565LE;
55                 break;
56         case BITMAP_PIXEL_FORMAT_ARGB8888:
57                 out = MEDIA_PIXEL_FORMAT_BGRA8888;
58                 break;
59         case BITMAP_PIXEL_FORMAT_R8G8B8A8:
60                 out = MEDIA_PIXEL_FORMAT_RGBA8888;
61                 break;
62         default:
63                 break;
64         }
65         return out;
66 }} // unnamed namespace
67
68 namespace Tizen { namespace Graphics
69 {
70 result
71 _CreateCoordinateTransformer(_ICoordinateSystemTransformer*& pTransformer, int srcResolution, _BaseScreenSize srcBaseScreenSize, Dimension destResolution, _BaseScreenSize destBaseScreenSize);
72 }} // Tizen::Graphics
73
74 namespace Tizen { namespace App
75 {
76
77 _AppResourceBitmapUtil::_AppResourceBitmapUtil(void)
78         : __physicalResolutionDim(0, 0)
79         , __physicalBaseScreenSize(BASE_SCREEN_SIZE_DEFAULT)
80         , __resolutionDirectories(L"")
81         , __sortedDensityDirectories()
82 {
83         for (int i = 0; i < DENSITY_MAX; i++)
84         {
85                 __sortedDensity[i] = DENSITY_NONE;
86         }
87         __physicalResolutionDim = _CoordinateSystem::GetInstance()->GetPhysicalResolutionDim();
88         __physicalBaseScreenSize = _CoordinateSystem::GetInstance()->GetPhysicalBaseScreenSize();
89 }
90
91 _AppResourceBitmapUtil::~_AppResourceBitmapUtil(void)
92 {
93 }
94
95 result
96 _AppResourceBitmapUtil::Construct(void)
97 {
98         int deviceDPI = 0;
99         result r = Tizen::System::_SystemInfoImpl::GetSysInfo(L"http://tizen.org/feature/screen.dpi", deviceDPI);
100         SysTryReturnResult(NID_APP, r == E_SUCCESS, r, "[%s] Failed to get Screen DPI", GetErrorMessage(r));
101
102         // 1. Get directory path matched device's resolution (e.g.720x1280)
103         if (GetDirectoryPath(DENSITY_NONE, __resolutionDirectories) == false)
104         {
105                 __resolutionDirectories = L"";
106                 SysLog(NID_APP, "Failed to get a Device Resolution Directory path");
107         }
108
109         // 2. Get screen density & directory path matched device's DPI (e.g.screen-density-xhigh)
110         if (deviceDPI >= DPI_FOR_XHIGH)
111         {
112                 __sortedDensity[0] = DENSITY_XHIGH;
113         }
114         else if (deviceDPI >= DPI_FOR_HIGH)
115         {
116                 __sortedDensity[0] = DENSITY_HIGH;
117         }
118         else if (deviceDPI >= DPI_FOR_MIDDLE)
119         {
120                 __sortedDensity[0] = DENSITY_MIDDLE;
121         }
122         else if (deviceDPI < DPI_FOR_MIDDLE && deviceDPI >= DPI_FOR_LOW)
123         {
124                 __sortedDensity[0] = DENSITY_LOW;
125         }
126         else
127         {
128                 __sortedDensity[0] = DENSITY_XHIGH;
129                 SysLog(NID_APP, "Failed to get a Device Density (DPI = %d)", deviceDPI);
130         }
131
132         if (GetDirectoryPath(__sortedDensity[0], __sortedDensityDirectories[0]) == false)
133         {
134                 __sortedDensityDirectories[0] = L"";
135                 SysLog(NID_APP, "Failed to get a Device Density Directory path");
136         }
137
138         // 3. Get screen density & directory path with fall back system (XHIGH-HIGH-MIDDLE-LOW)
139         int densityIndex = 1;
140
141         for (int currentDensity = DENSITY_XHIGH; currentDensity >= DENSITY_LOW; currentDensity--)
142         {
143                 SysAssert(densityIndex > DENSITY_NONE && densityIndex < DENSITY_MAX);
144
145                 if (static_cast<int>(__sortedDensity[0]) == currentDensity)
146                 {
147                         continue;
148                 }
149
150                 __sortedDensity[densityIndex] = static_cast<_Density>(currentDensity);
151
152                 if (GetDirectoryPath(__sortedDensity[densityIndex], __sortedDensityDirectories[densityIndex]) == false)
153                 {
154                         __sortedDensityDirectories[densityIndex] = L"";
155                         SysLog(NID_APP, "Failed to get a %dth Fall-Back Directory path", densityIndex);
156                 }
157
158                 densityIndex++;
159         }
160
161         return r;
162 }
163
164 result
165 _AppResourceBitmapUtil::Construct(const String& appId)
166 {
167         int deviceDPI = 0;
168         result r = Tizen::System::_SystemInfoImpl::GetSysInfo(L"http://tizen.org/feature/screen.dpi", deviceDPI);
169         SysTryReturnResult(NID_APP, r == E_SUCCESS, r, "[%s] Failed to get Screen DPI", GetErrorMessage(r));
170
171         // 1. Get directory path matched device's resolution (e.g.720x1280)
172         if (GetDirectoryPath(DENSITY_NONE, __resolutionDirectories, appId) == false)
173         {
174                 __resolutionDirectories = L"";
175                 SysLog(NID_APP, "Failed to get a Device Resolution Directory path");
176         }
177
178         // 2. Get screen density & directory path matched device's DPI (e.g.screen-density-xhigh)
179         if (deviceDPI >= DPI_FOR_XHIGH)
180         {
181                 __sortedDensity[0] = DENSITY_XHIGH;
182         }
183         else if (deviceDPI >= DPI_FOR_HIGH)
184         {
185                 __sortedDensity[0] = DENSITY_HIGH;
186         }
187         else if (deviceDPI >= DPI_FOR_MIDDLE)
188         {
189                 __sortedDensity[0] = DENSITY_MIDDLE;
190         }
191         else if (deviceDPI < DPI_FOR_MIDDLE && deviceDPI >= DPI_FOR_LOW)
192         {
193                 __sortedDensity[0] = DENSITY_LOW;
194         }
195         else
196         {
197                 __sortedDensity[0] = DENSITY_XHIGH;
198                 SysLog(NID_APP, "Failed to get a Device Density (DPI = %d)", deviceDPI);
199         }
200
201         if (GetDirectoryPath(__sortedDensity[0], __sortedDensityDirectories[0], appId) == false)
202         {
203                 __sortedDensityDirectories[0] = L"";
204                 SysLog(NID_APP, "Failed to get a Device Density Directory path");
205         }
206
207         // 3. Get screen density & directory path with fall back system (XHIGH-HIGH-MIDDLE-LOW)
208         int densityIndex = 1;
209
210         for (int currentDensity = DENSITY_XHIGH; currentDensity >= DENSITY_LOW; currentDensity--)
211         {
212                 SysAssert(densityIndex > DENSITY_NONE && densityIndex < DENSITY_MAX);
213
214                 if (static_cast<int>(__sortedDensity[0]) == currentDensity)
215                 {
216                         continue;
217                 }
218
219                 __sortedDensity[densityIndex] = static_cast<_Density>(currentDensity);
220
221                 if (GetDirectoryPath(__sortedDensity[densityIndex], __sortedDensityDirectories[densityIndex], appId) == false)
222                 {
223                         __sortedDensityDirectories[densityIndex] = L"";
224                         SysLog(NID_APP, "Failed to get a %dth Fall-Back Directory path", densityIndex);
225                 }
226
227                 densityIndex++;
228         }
229
230         return r;
231 }
232
233 // Get Resource DirectoryPath
234 bool
235 _AppResourceBitmapUtil::GetDirectoryPath(const _Density resourceDirectory, String& dirPath) const
236 {
237         const String& homePath(_AppInfo::GetAppRootPath() + L"res/");
238
239         switch (resourceDirectory)
240         {
241         case DENSITY_NONE:
242                 switch (__physicalResolutionDim.width)
243                 {
244                 case 720:
245                         dirPath = L"720x1280";
246                         break;
247
248                 case 480:
249                         dirPath = L"480x800";
250                         break;
251
252                 case 240:
253                         dirPath = L"240x400";
254                         break;
255
256                 case 320:
257                         dirPath = L"320x480";
258                         break;
259
260                 default:
261                         break;
262                 }
263                 break;
264
265         case DENSITY_XHIGH:
266                 dirPath = L"screen-density-xhigh";
267                 break;
268
269         case DENSITY_HIGH:
270                 dirPath = L"screen-density-high";
271                 break;
272
273         case DENSITY_MIDDLE:
274                 dirPath = L"screen-density-middle";
275                 break;
276
277         case DENSITY_LOW:
278                 dirPath = L"screen-density-low";
279                 break;
280
281         default:
282                 dirPath = L'\0';
283                 return false;
284         }
285
286         result r = dirPath.Insert(homePath, 0);
287         SysTryReturn(NID_APP, r == E_SUCCESS, false, r, "[%s] Failed to insert string.", GetErrorMessage(r));
288
289         if ( File::IsFileExist(dirPath) == false )
290         {
291                 dirPath = L'\0';
292                 return false;
293         }
294         return true;
295 }
296
297 bool
298 _AppResourceBitmapUtil::GetDirectoryPath(const _Density resourceDirectory, String& dirPath, const String& appId) const
299 {
300         PackageInfo* pPkgInfo = null;
301         pPkgInfo = _PackageManagerImpl::GetInstance()->GetPackageInfoN(appId);
302         _PackageInfoImpl* pPkgInfoImpl = _PackageInfoImpl::GetInstance(pPkgInfo);
303         SysTryReturn(NID_APP, pPkgInfoImpl != null, false, E_APP_NOT_INSTALLED, "[E_APP_NOT_INSTALLED] Failed to create the package info instance");
304
305         const String& homePath(pPkgInfoImpl->GetAppRootPath() + L"/res/");
306
307         delete pPkgInfo;
308
309         switch (resourceDirectory)
310         {
311         case DENSITY_NONE:
312                 switch (__physicalResolutionDim.width)
313                 {
314                 case 720:
315                         dirPath = L"720x1280";
316                         break;
317
318                 case 480:
319                         dirPath = L"480x800";
320                         break;
321
322                 case 240:
323                         dirPath = L"240x400";
324                         break;
325
326                 case 320:
327                         dirPath = L"320x480";
328                         break;
329
330                 default:
331                         break;
332                 }
333                 break;
334
335         case DENSITY_XHIGH:
336                 dirPath = L"screen-density-xhigh";
337                 break;
338
339         case DENSITY_HIGH:
340                 dirPath = L"screen-density-high";
341                 break;
342
343         case DENSITY_MIDDLE:
344                 dirPath = L"screen-density-middle";
345                 break;
346
347         case DENSITY_LOW:
348                 dirPath = L"screen-density-low";
349                 break;
350
351         default:
352                 dirPath = L'\0';
353                 return false;
354         }
355
356         result r = dirPath.Insert(homePath, 0);
357         SysTryReturn(NID_APP, r == E_SUCCESS, false, r, "[%s] Failed to insert string.", GetErrorMessage(r));
358
359         if ( File::IsFileExist(dirPath) == false )
360         {
361                 dirPath = L'\0';
362                 return false;
363         }
364         return true;
365 }
366
367 // Get Resource File Path
368 bool
369 _AppResourceBitmapUtil::GetFilePath(const String& directoryPath, const String& fileName, String& filePath) const
370 {
371         if (directoryPath == null)
372         {
373                 filePath = null;
374                 return false;
375         }
376
377         const String& normalizedPseudoPath = NormalizePath(fileName);
378         SysAssert(normalizedPseudoPath.StartsWith(L"/", 0));
379
380         filePath = directoryPath + normalizedPseudoPath;
381
382         return true;
383 }
384
385 // Normalizing Path
386 String
387 _AppResourceBitmapUtil::NormalizePath(const String& path) const
388 {
389         String normalizedPath = path;
390
391         normalizedPath.Replace(L'\\', L'/');
392
393         if (normalizedPath.StartsWith(L"/", 0) == false)
394         {
395                 result r = normalizedPath.Insert(L'/', 0);
396                 SysTryLog(NID_APP, r == E_SUCCESS, "[%s] Propagating.", GetErrorMessage(r));
397         }
398
399         return normalizedPath;
400 }
401
402 // Get Matched Resource File Path
403 result
404 _AppResourceBitmapUtil::GetResourcePath(const String& fileName, String& resourcePath, _Density& resourceDensity, bool& imageScaling) const
405 {
406         result r = E_SUCCESS;
407
408         // 1. Try to search resolution Folder
409         String resourcePathForResolution(L"");
410
411         if (__resolutionDirectories.IsEmpty() == false &&
412                         GetFilePath(__resolutionDirectories, fileName, resourcePathForResolution))
413         {
414                 if (File::IsFileExist(resourcePathForResolution))
415                 {
416                         resourcePath = resourcePathForResolution;
417                         resourceDensity = DENSITY_NONE;
418                         imageScaling = false;
419
420                         r = E_SUCCESS;
421                         return r;
422                 }
423         }
424
425         // 2. Try to search resource directory matched device's DPI
426         String resourcePathForDensity(L"");
427
428         if (__sortedDensityDirectories[0].IsEmpty() == false &&
429                         GetFilePath(__sortedDensityDirectories[0], fileName, resourcePathForDensity))
430         {
431                 if (File::IsFileExist(resourcePathForDensity))
432                 {
433                         resourcePath = resourcePathForDensity;
434                         resourceDensity = __sortedDensity[0];
435                         imageScaling = _CoordinateSystem::GetInstance()->IsTransformEnabled();
436
437                         r = E_SUCCESS;
438                         return r;
439                 }
440         }
441
442         // 3. Try to find the alternative path with fall back
443         int fallbackIndex = 1;
444         String alternativeResourcePath(L"");
445
446         for (int findingDensity = DENSITY_XHIGH; findingDensity > DENSITY_LOW; findingDensity--)
447         {
448                 if (__sortedDensityDirectories[fallbackIndex].IsEmpty() == false &&
449                                 GetFilePath(__sortedDensityDirectories[fallbackIndex], fileName, alternativeResourcePath))
450                 {
451                         if (File::IsFileExist(alternativeResourcePath))
452                         {
453                                 resourcePath = alternativeResourcePath;
454                                 resourceDensity = __sortedDensity[fallbackIndex];
455                                 imageScaling = true;
456
457                                 r = E_SUCCESS;
458                                 return r;
459                         }
460                 }
461                 fallbackIndex++;
462         }
463
464         SysTryReturn(NID_APP, r == E_SUCCESS, E_FILE_NOT_FOUND, E_FILE_NOT_FOUND, "[E_FILE_NOT_FOUND] The specified file cannot be found.");
465         return r;
466 }
467
468 // GetBitmapN
469 Bitmap*
470 _AppResourceBitmapUtil::GetBitmapN(const String& resourcePath, const _Density resourceDensity,
471                                                                    BitmapPixelFormat pixelFormat, bool imageScaling, const Color* pChromaKeyColor) const
472 {
473         ClearLastResult();
474         SysTryReturn(NID_APP, (pixelFormat > BITMAP_PIXEL_FORMAT_MIN && pixelFormat < BITMAP_PIXEL_FORMAT_MAX), null,
475                                 E_UNSUPPORTED_FORMAT, "[E_UNSUPPORTED_FORMAT] The image file format or specified pixel format(%d) is not supported.", pixelFormat);
476
477         result r = E_SUCCESS;
478
479         unique_ptr<Bitmap> pBitmap;
480
481         if (!pChromaKeyColor && imageScaling == false)  // NonScaling
482         {
483                 pBitmap.reset(new (std::nothrow) Bitmap());
484                 SysTryReturn(NID_APP, pBitmap != null, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
485
486                 r = _BitmapImpl::GetInstance(*pBitmap)->Construct(resourcePath, pixelFormat);
487                 SysTryReturn(NID_APP, r == E_SUCCESS, null, r, "[%s] Propagating.", GetErrorMessage(r));
488
489                 return pBitmap.release();
490         }
491         else    // Scaling
492         {
493                 MediaPixelFormat format = ConvertBitmapPixelFormatToMediaPixelFormat(pixelFormat);
494                 int imageWidth(-1);
495                 int imageHeight(-1);
496
497                 std::unique_ptr<ByteBuffer> pBuffer(_ImageDecoder::DecodeToBufferN(resourcePath, format, imageWidth, imageHeight));
498                 r = GetLastResult();
499                 SysTryReturn(NID_APP, r == E_SUCCESS, null, r, "[%s] Propagating.", GetErrorMessage(r));
500                 SysTryReturn(NID_APP, pBuffer != null, null, E_SYSTEM, "[E_SYSTEM] A system error has occurred.");
501
502                 pBitmap.reset(_BitmapImpl::GetNonScaledBitmapN(*pBuffer, Dimension(imageWidth, imageHeight), pixelFormat));
503                 r = GetLastResult();
504                 SysTryReturn(NID_APP, r == E_SUCCESS, null, r, "[%s] Propagating.", GetErrorMessage(r));
505                 SysTryReturn(NID_APP, pBitmap != null, null, E_SYSTEM, "[E_SYSTEM] A system error has occurred.");
506
507                 int resourceLogicalCoordinate = __physicalResolutionDim.width;
508
509                 switch (resourceDensity)
510                 {
511                 case DENSITY_XHIGH:
512                         resourceLogicalCoordinate = 720;
513                         break;
514
515                 case DENSITY_HIGH:
516                         resourceLogicalCoordinate = 480;
517                         break;
518
519                 case DENSITY_MIDDLE:
520                         resourceLogicalCoordinate = 320;
521                         break;
522
523                 case DENSITY_LOW:
524                         resourceLogicalCoordinate = 240;
525                         break;
526
527                 default:
528                         break;
529                 }
530
531                 _ICoordinateSystemTransformer* pTempXformer(null);
532                 r = _CreateCoordinateTransformer(pTempXformer,
533                                         resourceLogicalCoordinate, __physicalBaseScreenSize,
534                                         Dimension(_CoordinateSystem::GetInstance()->GetLogicalResolutionInt(), _CoordinateSystem::GetInstance()->GetLogicalResolutionInt()), _CoordinateSystem::GetInstance()->GetLogicalBaseScreenSize());
535
536                 std::unique_ptr<_ICoordinateSystemTransformer> pXformer(pTempXformer);
537                 SysTryReturn(NID_APP, pXformer != null, null, E_SYSTEM, "[E_SYSTEM] A system error has occurred.");
538                 SysTryReturn(NID_APP, r == E_SUCCESS, null, r, "[%s] Propagating.", GetErrorMessage(r));
539
540                 Dimension baseImageSize = pXformer->Transform(Dimension(imageWidth, imageHeight));
541                 r = GetLastResult();
542                 SysTryReturn(NID_APP, r == E_SUCCESS, null, E_SYSTEM, "[E_SYSTEM] A system error has occurred.");
543
544                 r = pBitmap->Scale(baseImageSize);
545                 SysTryReturn(NID_APP, r == E_SUCCESS, null, E_SYSTEM, "[E_SYSTEM] A system error has occurred.");
546         }
547
548         if (pChromaKeyColor != null)
549         {
550                 r = pBitmap->SetMaskingColor(pChromaKeyColor);
551                 SysTryReturn(NID_APP, r == E_SUCCESS, null, r, "[%s] Propagating.", GetErrorMessage(r));
552         }
553
554         SetLastResult(E_SUCCESS);
555
556         return pBitmap.release();
557 }
558
559 }} // Tizen::App