[3.0] Third party ImageResampler library added.
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / emscripten / emscripten-platform-abstraction.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include "emscripten-platform-abstraction.h"
19
20 // EXTERNAL INCLUDES
21 #include <set>
22 #include <stdint.h>
23 #include <cstring>
24 #include <SDL_surface.h>
25 #include <SDL_image.h>
26 #include "emscripten/emscripten.h"
27 #include "emscripten-callbacks.h"
28
29 #define EM_LOG(x); // EM_ASM( console.log( x ) );
30
31
32 // INTERNAL INCLUDES
33 #include <dali/integration-api/platform-abstraction.h>
34 #include <dali/devel-api/common/ref-counted-dali-vector.h>
35
36 namespace
37 {
38
39 Dali::Integration::BitmapPtr LoadResourceEncodedImage( Dali::RefCountedVector<uint8_t>* encodedBlob )
40 {
41   Dali::Integration::BitmapPtr bitmapPtr = NULL;
42
43   if( encodedBlob != 0 )
44   {
45     const size_t blobSize     = encodedBlob->GetVector().Size();
46     uint8_t * const blobBytes = &(encodedBlob->GetVector()[0]);
47     DALI_ASSERT_DEBUG( blobSize > 0U );
48     DALI_ASSERT_DEBUG( blobBytes != 0U );
49
50     if( blobBytes != 0 && blobSize > 0U )
51     {
52
53       SDL_RWops *memory = SDL_RWFromMem(blobBytes, blobSize);
54
55       if(!memory)
56       {
57         printf("  Error Null pointer from SDL RW memory?\n");
58       }
59
60       SDL_Surface *surface = IMG_Load_RW(memory, 0);
61
62       if(surface)
63       {
64         bitmapPtr = Dali::Integration::Bitmap::New( Dali::Integration::Bitmap::BITMAP_2D_PACKED_PIXELS,
65                                                     Dali::ResourcePolicy::OWNED_DISCARD ); // DISCARD; Dali manages
66
67         Dali::Integration::Bitmap::PackedPixelsProfile* packedProfile = bitmapPtr->GetPackedPixelsProfile();
68         DALI_ASSERT_ALWAYS(packedProfile);
69
70         unsigned char bytesPerPixel = surface->format->BytesPerPixel;
71
72         Dali::Integration::PixelBuffer* pixels = NULL;
73
74         unsigned char targetBytesPerPixel = 3; // bytesPerPixel;
75
76         // SDL in emscripten returns us a 4byteperpixel image regardless of rgb/png etc
77         // Theres no apparent way to differentiate an image with an alpha channel
78         // In Dali if an image has an alpha channel it gets sorted. This introduces odd artifacts on rotation
79         // as the sorting algorithm presumes front on view.
80         // So here well just support pngs with an alpha channel.
81         // We're poking around in the format as emscripten currently lacks a file memory api where we could use
82         // Dali's machinery to read the format.
83         unsigned char *pBytes = blobBytes;
84
85         if( 0x89 == *(pBytes+0) && 0x50 == *(pBytes+1) ) // magic bytes for png_all_filters
86         {
87           pBytes+=8; // 8 bytes for header
88           pBytes+=4; // 4 bytes for chunk length
89           pBytes+=4; // 4 bytes for chunk type
90           // ihdr data (must be first chunk)
91           pBytes+=4; // 4 for width,height
92           pBytes+=4;
93           pBytes+=1; // 1 for bit depth
94           unsigned char ihdr_colorType= *pBytes;    // 1 for bit colorType
95           if( (4 == ihdr_colorType ||               // 4 is 8,16 bit depth with alpha LA
96                6 == ihdr_colorType) )               // 6 is 8,16 bit depth with alpha RGBA
97           {
98             targetBytesPerPixel = 4;
99           }
100         }
101
102         if(3 == targetBytesPerPixel)
103         {
104           pixels = packedProfile->ReserveBuffer(Dali::Pixel::RGB888,
105                                                 surface->w, surface->h,
106                                                 surface->w, surface->h);
107         }
108         else if(4 == targetBytesPerPixel)
109         {
110           pixels = packedProfile->ReserveBuffer(Dali::Pixel::RGBA8888,
111                                                 surface->w, surface->h,
112                                                 surface->w, surface->h);
113         }
114         else
115         {
116           DALI_ASSERT_ALWAYS(0 && "bad bytes per pixel");
117         }
118
119         unsigned char* fromPtr = static_cast<unsigned char*>(surface->pixels);
120
121         int stride = surface->pitch;
122         int index = 0;
123         for(int h = 0; h < surface->h; ++h)
124         {
125           for(int w = 0; w < (surface->w*bytesPerPixel); w+=bytesPerPixel)
126           {
127             for(int j = 0; j < targetBytesPerPixel; ++j)
128             {
129               pixels[ index++ ] = *( (fromPtr + (h * stride) ) + w + j );
130             }
131           }
132         }
133       } // if surface
134       else
135       {
136         printf("  Error empty surface when decoding image? (SDL RW Memory ptr=%llx) %s. %d\n", (long long)(memory), SDL_GetError(), blobSize);
137       }
138
139     } // if blobSize
140     else
141     {
142       printf(" Error No bytes in image?\n");
143     }
144
145   } // if encodedBlob
146   else
147   {
148     printf("  Error Null pointer given for decoding image?\n");
149   }
150
151   if(bitmapPtr)
152   {
153     int x = 0;
154     EM_ASM( console.log( "LoadResourceEncodedImage: Image:-" ) );
155     x = EM_ASM_INT({
156         console.log( $0 ) }, bitmapPtr->GetImageWidth() );
157     x = EM_ASM_INT({
158         console.log( $0 ) }, bitmapPtr->GetImageHeight() );
159     x = EM_ASM_INT({
160         console.log( $0 ) }, bitmapPtr->GetBufferSize() );
161
162   }
163   else
164   {
165     EM_ASM( console.log( "LoadResourceEncodedImage: no bitmap data?" ) );
166   }
167
168   return bitmapPtr;
169 }
170
171 } // anon namespace
172
173 namespace Dali
174 {
175
176 EmscriptenPlatformAbstraction::EmscriptenPlatformAbstraction()
177   :
178     mSize(10,10)
179 {
180 }
181
182
183 EmscriptenPlatformAbstraction::~EmscriptenPlatformAbstraction()
184 {
185 }
186
187 void EmscriptenPlatformAbstraction::GetTimeMicroseconds(unsigned int &seconds, unsigned int &microSeconds)
188 {
189   double current = EM_ASM_DOUBLE_V({ return new Date().getTime(); }); // getTime() in ms
190
191   seconds         = static_cast<unsigned int>(current/1000.0);
192   microSeconds    = (static_cast<unsigned int>(current) - seconds*1000.0) * 1000;
193 }
194
195 void EmscriptenPlatformAbstraction::Suspend()
196 {
197   DALI_ASSERT_ALWAYS("!Not Implemented");
198 }
199
200 void EmscriptenPlatformAbstraction::Resume()
201 {
202   DALI_ASSERT_ALWAYS("!Not Implemented");
203 }
204
205 ImageDimensions EmscriptenPlatformAbstraction::GetClosestImageSize( const std::string& filename,
206                                                              ImageDimensions size,
207                                                              FittingMode::Type fittingMode,
208                                                              SamplingMode::Type samplingMode,
209                                                              bool orientationCorrection )
210 {
211   return Dali::Internal::Emscripten::LoadImageMetadata(filename, size, fittingMode, samplingMode, orientationCorrection);
212 }
213
214 ImageDimensions EmscriptenPlatformAbstraction::GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
215                                                              ImageDimensions size,
216                                                              FittingMode::Type fittingMode,
217                                                              SamplingMode::Type samplingMode,
218                                                              bool orientationCorrection )
219 {
220   // @todo
221   return Dali::ImageDimensions(); // Dali::Internal::Emscripten::LoadImageMetadata(filename, size, fittingMode, samplingMode, orientationCorrection);
222 }
223
224 Integration::ResourcePointer EmscriptenPlatformAbstraction::LoadResourceSynchronously( const Integration::ResourceType& resourceType, const std::string& resourcePath )
225 {
226   Integration::ResourcePointer ret;
227
228   switch(resourceType.id)
229   {
230     case Integration::ResourceBitmap:
231     {
232       const Integration::BitmapResourceType& bitmapResource( static_cast<const Integration::BitmapResourceType&>(resourceType) );
233
234       Integration::BitmapPtr bitmapPtr = Dali::Internal::Emscripten::GetImage( bitmapResource.size,
235                                                                                bitmapResource.scalingMode,
236                                                                                bitmapResource.samplingMode,
237                                                                                bitmapResource.orientationCorrection,
238                                                                                resourcePath );
239
240       ret = bitmapPtr;
241     }
242     break;
243     case Integration::ResourceNativeImage:
244     {
245     }
246     break;
247     case Integration::ResourceTargetImage:
248     {
249     }
250     break;
251   } // switch(resourceType->id)
252
253   return ret;
254 }
255
256 void EmscriptenPlatformAbstraction::LoadResource(const Integration::ResourceRequest& request)
257 {
258   std::string path = request.GetPath();
259
260   Integration::ResourceType *type            = request.GetType();
261   Integration::ResourceId   resourceId       = request.GetId();
262   Integration::ResourcePointer resourcePtr   = request.GetResource();
263
264   if( type )
265   {
266     switch(type->id)
267     {
268       case Integration::ResourceBitmap:
269       {
270         Integration::BitmapPtr bitmapPtr = NULL;
271
272         if( NULL == request.GetResource().Get()  )
273         {
274           const Integration::BitmapResourceType& bitmapResource( static_cast<const Integration::BitmapResourceType&>(*type) );
275
276           Integration::BitmapPtr bitmapPtr = Dali::Internal::Emscripten::GetImage( bitmapResource.size,
277                                                                                    bitmapResource.scalingMode,
278                                                                                    bitmapResource.samplingMode,
279                                                                                    bitmapResource.orientationCorrection,
280                                                                                    path );
281
282
283
284         }
285         else
286         {
287           // 2) load it (usually on worker thread)
288           // DALI_LOG_TRACE_METHOD( mLogFilter );
289           // DALI_LOG_INFO(mLogFilter, Debug::Verbose, "%s(%s)\n", __FUNCTION__, request.GetPath().c_str());
290
291           bitmapPtr = LoadResourceEncodedImage( reinterpret_cast<Dali::RefCountedVector<uint8_t>*>( request.GetResource().Get() ) );
292         }
293
294         if( bitmapPtr )
295         {
296           mResourceQueue.push( ResourceIdBitmapPair( resourceId, bitmapPtr ) );
297         }
298
299       }
300       break;
301       case Integration::ResourceNativeImage:
302       {
303         printf("EmscriptenPlatformAbstraction::LoadResource ResourceNativeImage\n");
304       }
305       break;
306       case Integration::ResourceTargetImage:
307       {
308         printf("EmscriptenPlatformAbstraction::LoadResource ResourceTargetImage\n");
309       }
310       break;
311     } // switch(id)
312
313   } // if(type)
314
315 }
316
317 void EmscriptenPlatformAbstraction::SaveResource(const Integration::ResourceRequest& request)
318 {
319   DALI_ASSERT_ALWAYS("!Not Implemented");
320 }
321
322 Integration::BitmapPtr EmscriptenPlatformAbstraction::DecodeBuffer( const Integration::ResourceType& resourceType, uint8_t * buffer, size_t bufferSize )
323 {
324   return Integration::BitmapPtr();
325 }
326
327 void EmscriptenPlatformAbstraction::CancelLoad(Integration::ResourceId id, Integration::ResourceTypeId typeId)
328 {
329   DALI_ASSERT_ALWAYS("!Not Implemented");
330 }
331
332 void EmscriptenPlatformAbstraction::GetResources(Integration::ResourceCache& cache)
333 {
334   while( !mResourceQueue.empty() )
335   {
336     Integration::ResourceId    resourceId  = mResourceQueue.front().first;
337     Integration::BitmapPtr     bitmapPtr   = mResourceQueue.front().second;
338
339     cache.LoadResponse( resourceId,
340                         Integration::ResourceBitmap,
341                         bitmapPtr,
342                         Integration::RESOURCE_COMPLETELY_LOADED );
343     mResourceQueue.pop();
344   }
345 }
346
347 bool EmscriptenPlatformAbstraction::IsLoading()
348 {
349   EM_LOG("EmscriptenPlatformAbstraction::IsLoading");
350   return false;
351 }
352
353 const std::string& EmscriptenPlatformAbstraction::GetDefaultFontFamily() const
354 {
355   EM_LOG("EmscriptenPlatformAbstraction::GetDefaultFontFamily");
356   DALI_ASSERT_ALWAYS("!Not Implemented");
357   return mGetDefaultFontFamilyResult;
358 }
359
360 int EmscriptenPlatformAbstraction::GetDefaultFontSize() const
361 {
362   EM_LOG("EmscriptenPlatformAbstraction::GetDefaultFontSize");
363   return 12;
364 }
365
366 void EmscriptenPlatformAbstraction::SetDpi (unsigned int /* dpiHorizontal*/, unsigned int /* dpiVertical */)
367 {
368
369 }
370
371
372 bool EmscriptenPlatformAbstraction::LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer )  const
373 {
374   EM_LOG("EmscriptenPlatformAbstraction::LoadFile");
375   return false;
376 }
377
378 bool EmscriptenPlatformAbstraction::SaveFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const
379 {
380   EM_LOG("EmscriptenPlatformAbstraction::SaveFile");
381
382   DALI_ASSERT_ALWAYS("!Unimplemented");
383   return false;
384 }
385
386 bool EmscriptenPlatformAbstraction::LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const
387 {
388   EM_LOG("EmscriptenPlatformAbstraction::LoadShaderBinaryFile");
389   return false;
390 }
391
392 bool EmscriptenPlatformAbstraction::SaveShaderBinaryFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const
393 {
394   EM_LOG("EmscriptenPlatformAbstraction::SaveShaderBinaryFile");
395
396   DALI_ASSERT_ALWAYS("!Unimplemented");
397   return false;
398 }
399
400 void EmscriptenPlatformAbstraction::JoinLoaderThreads()
401 {
402   DALI_ASSERT_ALWAYS("!Unimplemented");
403 }
404
405 void EmscriptenPlatformAbstraction::UpdateDefaultsFromDevice()
406 {
407   DALI_ASSERT_ALWAYS("!Unimplemented");
408   mGetDefaultFontFamilyResult+=1.0f;
409 }
410
411 void EmscriptenPlatformAbstraction::IncrementGetTimeResult(size_t milliseconds)
412 {
413 }
414
415 } // Dali