f5e1f5c4e0aff90bf41d9350f0e4f049603b4101
[platform/core/location/maps-plugin-here.git] / src / here_view.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
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 #include "here_view.h"
18 #include <Elementary.h>
19
20 using namespace HERE_PLUGIN_NAMESPACE_PREFIX;
21
22 static const char SIG_LOADED[] = "loaded";
23
24
25 HERE_PLUGIN_BEGIN_NAMESPACE
26
27 HereView::HereView()
28 {
29         __map = NULL;
30
31         __img = NULL;
32         __ctx = NULL;
33         __sfc = NULL;
34         __cfg = NULL;
35         __gl = NULL;
36         __api = NULL;
37
38         __isInitialized = false;
39
40         __x = 0;
41         __y = 0;
42         __w = 0;
43         __h = 0;
44
45         __idler = NULL;
46         __redraw = false;
47         __readyCb = NULL;
48 }
49
50 HereView::~HereView()
51 {
52 }
53
54 here_error_e HereView::init(maps_view_h view, maps_plugin_map_view_ready_cb callback)
55 {
56         if (!view)
57                 return HERE_ERROR_INVALID_PARAMETER;
58
59         __idler = ecore_idler_add(__idlerCb, (void*)view);
60
61         here_error_e error = HERE_ERROR_NONE;
62         int error2 = MAPS_ERROR_NONE;
63
64         do {
65                 error2 = maps_view_get_viewport(view, &__img);
66                 if (error2 != MAPS_ERROR_NONE) break;
67
68                 error2 = maps_view_get_screen_location(view, &__x, &__y, &__w, &__h);
69                 if (error2 != MAPS_ERROR_NONE) break;
70
71                 error = initOpenGL();
72                 if (error != HERE_ERROR_NONE) break;
73
74                 error = initOpenGLSurface(view);
75                 if (error != HERE_ERROR_NONE) break;
76
77                 error = initMap(view, callback);
78         } while (0);
79
80         if (error == HERE_ERROR_NONE && error2 != MAPS_ERROR_NONE)
81                 error = (here_error_e)ConvertToHereError(error2);
82
83         return error;
84 }
85
86 here_error_e HereView::initOpenGL()
87 {
88         __cfg = evas_gl_config_new();
89         if (!__cfg) {
90                 MAPS_LOGE("evas_gl_config_new() failed");
91                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
92         }
93
94         __cfg->color_format = EVAS_GL_RGBA_8888;    // Surface Color Format
95         __cfg->depth_bits   = EVAS_GL_DEPTH_NONE;   // Surface Depth Format
96         __cfg->stencil_bits = EVAS_GL_STENCIL_NONE; // Surface Stencil Format
97         __cfg->options_bits = EVAS_GL_OPTIONS_DIRECT; // Configuration options (here, no extra options)
98
99         __gl = evas_gl_new(evas_object_evas_get(__img));
100         if (!__gl) {
101                 MAPS_LOGE("evas_gl_new() failed");
102                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
103         }
104
105         __api = evas_gl_api_get(__gl);
106         if (!__api) {
107                 MAPS_LOGE("evas_gl_api_get() failed");
108                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
109         }
110
111         __ctx = evas_gl_context_create(__gl, NULL);
112         if (!__ctx) {
113                 MAPS_LOGE("evas_gl_context_create() failed");
114                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
115         }
116
117         return HERE_ERROR_NONE;
118 }
119
120 here_error_e HereView::initOpenGLSurface(maps_view_h view)
121 {
122         if (!view || !__gl || !__cfg || !__img || !__ctx)
123                 return HERE_ERROR_INVALID_PARAMETER;
124
125         evas_object_image_pixels_get_callback_set(__img, NULL, NULL);
126
127         if (__sfc) {
128                 evas_object_image_native_surface_set(__img, NULL);
129                 evas_gl_surface_destroy(__gl, __sfc);
130         }
131
132         __w = MAX(__w, 1);
133         __h = MAX(__h, 1);
134
135         evas_object_image_size_set(__img, __w, __h);
136
137         Evas_Native_Surface ns;
138         __sfc = evas_gl_surface_create(__gl, __cfg, __w, __h);
139         if (!__sfc) {
140                 MAPS_LOGE("evas_gl_surface_create() failed");
141                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
142         }
143
144         if (!evas_gl_native_surface_get(__gl, __sfc, &ns)) {
145                 evas_gl_make_current(__gl, NULL, NULL);
146                 evas_gl_surface_destroy(__gl, __sfc);
147                 __sfc = NULL;
148                 MAPS_LOGE("evas_gl_native_surface_get() faile");
149                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
150         }
151
152         evas_object_image_native_surface_set(__img, &ns);
153         evas_object_image_pixels_get_callback_set(__img, __pixelGetCb, view);
154         __isInitialized = true;
155
156         return HERE_ERROR_NONE;
157 }
158
159 here_error_e HereView::initMap(maps_view_h view,  maps_plugin_map_view_ready_cb callback)
160 {
161         if (!view)
162                 return HERE_ERROR_INVALID_PARAMETER;
163
164         __map = new (std::nothrow) GeoTiledMap();
165         if (!__map)
166                 return HERE_ERROR_OUT_OF_MEMORY;
167
168         __readyCb = callback;
169
170         __map->SetReadyMapSignal((GeoTiledMap::ReadyMapSignalFunctor)__readyMapCb, (void *)view);
171         __map->SetEvasGlApi(__api);
172         __map->SetMapSize(Dimension(__w, __h));
173
174         __visualObjects.set(__map, evas_object_evas_get(__img));
175
176         return HERE_ERROR_NONE;
177 }
178
179 here_error_e HereView::close(maps_view_h view)
180 {
181         if (!view)
182                 return HERE_ERROR_INVALID_PARAMETER;
183
184         __isInitialized = false;
185
186         __visualObjects.set(NULL, NULL);
187
188         if (__img)
189                 evas_object_image_pixels_get_callback_set(__img, NULL, NULL);
190
191         if (__idler)
192                 ecore_idler_del(__idler);
193
194         if (__map) {
195                 __map->SetUpdateMapSignal(NULL);
196                 delete __map;
197         }
198
199         /* clear Open GL */
200         if (__gl) {
201                 if (__sfc && __ctx)
202                         evas_gl_make_current(__gl, __sfc, __ctx);
203
204                 if (__sfc) {
205                         evas_object_image_native_surface_set(__img, NULL);
206                         evas_gl_surface_destroy(__gl, __sfc);
207                 }
208
209                 if (__ctx)
210                         evas_gl_context_destroy(__gl, __ctx);
211
212                 evas_gl_free(__gl);
213                 __gl = NULL;
214         }
215
216         if (__cfg)
217                 evas_gl_config_free(__cfg);
218
219         return HERE_ERROR_NONE;
220 }
221
222 void HereView::__readyMapCb(void *data)
223 {
224         HereView *hv = NULL;
225         int maps_error = maps_view_get_maps_plugin_view_handle((maps_view_h)data, (void**)&hv);
226         if (maps_error != MAPS_ERROR_NONE || !hv) return;
227
228         if (hv->__readyCb)
229                 hv->__readyCb(data);
230 }
231
232 void HereView::__pixelGetCb(void *data, Evas_Object *obj)
233 {
234         HereView *hv = NULL;
235         int maps_error = maps_view_get_maps_plugin_view_handle(data, (void**)&hv);
236         if (maps_error != MAPS_ERROR_NONE || !hv ||
237                 !hv->__map || !hv->__gl || !hv->__sfc || !hv->__ctx) return;
238
239         evas_gl_make_current(hv->__gl, hv->__sfc, hv->__ctx);
240         hv->__map->PaintMap(hv->__w, hv->__h);
241 }
242
243 void HereView::__renderingCb(void *data)
244 {
245         if (!data) return;
246         evas_object_image_pixels_dirty_set((Evas_Object*)data, EINA_TRUE);
247 }
248
249 void HereView::setMapType(maps_view_h view)
250 {
251         if (!view)
252                 return;
253
254         /* When the theme is changed, clear cache */
255         maps_view_type_e map_type;
256         maps_view_get_type(view, &map_type);
257
258         bool buildings_enabled = false;
259         maps_view_get_buildings_enabled(view, &buildings_enabled);
260
261         bool traffic_enabled = false;
262         maps_view_get_traffic_enabled(view, &traffic_enabled);
263
264         bool public_transit_enabled = false;
265         maps_view_get_public_transit_enabled(view, &public_transit_enabled);
266
267         GeoTiledMap::MapType hereMapType = HereUtils::Convert(map_type, buildings_enabled,
268                                                 traffic_enabled, public_transit_enabled);
269
270         if (hereMapType != __map->GetMapType())
271         {
272                 MAPS_LOGD("Clear cache, because map type is changed.");
273                 __map->ClearCache();
274 #ifdef TIZEN_SUPPORT_TILE_FILE_CACHE
275                 __map->ClearTileFileCache();
276 #endif
277                 __map->SetMapType(hereMapType);
278         }
279 }
280
281 here_error_e HereView::renderMap(maps_view_h view, const maps_coordinates_h coord, double zoom, double angle)
282 {
283         if (!view || !coord)
284                 return HERE_ERROR_INVALID_PARAMETER;
285
286         if (!__isInitialized || !__map || !__api)
287                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
288
289         /* set map type */
290         setMapType(view);
291
292         /* resize window */
293         int x, y, w, h;
294         maps_view_get_screen_location(view, &x, &y, &w, &h);
295         __w = MAX(__w, 1);
296         __h = MAX(__h, 1);
297
298         if (x != __x || y != __y || w != __w || h != __h) {
299                 __x = x;
300                 __y = y;
301                 __w = w;
302                 __h = h;
303
304                 __api->glViewport(0, 0, __w, __h);
305                 __map->SetMapSize(Dimension(__w, __h));
306                 initOpenGLSurface(view);
307         }
308
309         /* callback */
310         GeoTiledMap::UpdateMapSignalFunctor callback = std::tr1::bind(&__renderingCb, __img);
311         __map->SetUpdateMapSignal(callback);
312
313         /* zoom level */
314         if (__map->GetZoomLevel() != zoom) {
315                 __map->SetZoomLevel(zoom, false);
316         }
317
318         /* angle */
319         if (__map->GetAngle() != angle) {
320                 __map->SetAngle(angle);
321         }
322
323         /* center */
324         double lat, lng;
325         maps_coordinates_get_latitude(coord, &lat);
326         maps_coordinates_get_longitude(coord, &lng);
327
328         GeoCoordinates geoCoord(lat, lng);
329         __map->SetCenter(geoCoord);
330
331         return HERE_ERROR_NONE;
332 }
333
334 here_error_e HereView::moveCenter(maps_view_h view, int delta_x, int delta_y)
335 {
336         if (!view)
337                 return HERE_ERROR_INVALID_PARAMETER;
338
339         if (!__isInitialized || !__map)
340                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
341
342         if (delta_x == 0 && delta_y == 0)
343                 return HERE_ERROR_NONE;
344
345         __map->Pan(delta_x, delta_y);
346
347         return HERE_ERROR_NONE;
348 }
349
350 here_error_e HereView::getCenter(maps_view_h view, maps_coordinates_h *center)
351 {
352         if (!view || !center)
353                 return HERE_ERROR_INVALID_PARAMETER;
354
355         if (!__isInitialized || !__map)
356                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
357
358         GeoCoordinates geoCoord = __map->GetCenter();
359         if (*center == NULL) {
360                 maps_coordinates_create(geoCoord.GetLatitude(), geoCoord.GetLongitude(), center);
361         } else {
362                 maps_coordinates_set_latitude(*center, geoCoord.GetLatitude());
363                 maps_coordinates_set_longitude(*center, geoCoord.GetLongitude());
364         }
365
366         return HERE_ERROR_NONE;
367 }
368
369 here_error_e HereView::setScalebarEnabled(maps_view_h view, bool enable)
370 {
371         if (!view)
372                 return HERE_ERROR_INVALID_PARAMETER;
373
374         if (!__isInitialized || !__map)
375                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
376
377         __map->SetScalebar(enable);
378
379         return HERE_ERROR_NONE;
380 }
381
382 here_error_e HereView::getScalebarEnabled(maps_view_h view, bool *enabled)
383 {
384         if (!view || !enabled)
385                 return HERE_ERROR_INVALID_PARAMETER;
386
387         if (!__isInitialized || !__map)
388                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
389
390         *enabled = __map->GetScalebar();
391         return HERE_ERROR_NONE;
392 }
393
394 here_error_e HereView::convertScreenToGeolocation(maps_view_h view, int x, int y, maps_coordinates_h *coord)
395 {
396         if (!view || !coord)
397                 return HERE_ERROR_INVALID_PARAMETER;
398
399         if (!__isInitialized || !__map)
400                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
401
402         Tizen::Maps::Point point(x, y);
403         GeoCoordinates geoCoord = __map->ScreenPositionToCoordinate(point);
404         double lat = geoCoord.GetLatitude();
405         double lng = geoCoord.GetLongitude();
406
407         int error = maps_coordinates_create(lat, lng, coord);
408         if (error != MAPS_ERROR_NONE)
409                 return (here_error_e)ConvertToHereError(error);
410
411         return HERE_ERROR_NONE;
412 }
413
414 here_error_e HereView::convertGeolocationToScreen(maps_view_h view, const maps_coordinates_h coord, int *x, int *y)
415 {
416         if (!view || !x || !y)
417                 return HERE_ERROR_INVALID_PARAMETER;
418
419         if (!__isInitialized || !__map)
420                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
421
422         double lat, lng;
423         maps_coordinates_get_latitude(coord, &lat);
424         maps_coordinates_get_longitude(coord, &lng);
425         GeoCoordinates geoCoord(lat, lng);
426         Tizen::Maps::Point point = __map->CoordinateToScreenPosition(geoCoord);
427
428         *x = point.x;
429         *y = point.y;
430
431         return HERE_ERROR_NONE;
432 }
433
434 here_error_e HereView::getMinZoomLevel(maps_view_h view, int *zoom)
435 {
436         if (!view || !zoom)
437                 return HERE_ERROR_INVALID_PARAMETER;
438
439         if (!__isInitialized || !__map)
440                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
441
442         *zoom = (int)__map->GetMinimumZoomLevel();
443
444         return HERE_ERROR_NONE;
445 }
446
447 here_error_e HereView::getMaxZoomLevel(maps_view_h view, int *zoom)
448 {
449         if (!view || !zoom)
450                 return HERE_ERROR_INVALID_PARAMETER;
451
452         if (!__isInitialized || !__map)
453                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
454
455         *zoom = (int)__map->GetMaximumZoomLevel();
456
457         return HERE_ERROR_NONE;
458 }
459
460 here_error_e HereView::onViewObject(maps_view_h view, const maps_view_object_h object, maps_view_object_operation_e operation)
461 {
462         if (!view || !object ||
463                 operation < MAPS_VIEW_OBJECT_ADD || operation > MAPS_VIEW_OBJECT_REMOVE)
464                 return HERE_ERROR_INVALID_PARAMETER;
465
466         if (!__isInitialized || !__map)
467                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
468
469         if (__map->GetRootPixmap())
470                 __processViewObject(view, object, operation);
471         else
472                 __pendingObjects.push_back(std::make_pair(object, operation));
473
474         return HERE_ERROR_NONE;
475 }
476
477 Eina_Bool HereView::__idlerCb(void *data)
478 {
479         HereView *hv = NULL;
480         int maps_error = maps_view_get_maps_plugin_view_handle(data, (void**)&hv);
481         if (maps_error != MAPS_ERROR_NONE || !hv) return true;
482         if (!hv->__map || !hv->__map->GetRootPixmap()) return true;
483
484         while (hv->__pendingObjects.size()) {
485                 PendingObject pending = hv->__pendingObjects.front();
486                 hv->__pendingObjects.pop_front();
487                 maps_view_object_h object = pending.first;
488                 maps_view_object_operation_e operation = pending.second;
489
490                 __processViewObject(data, object, operation);
491         }
492         return true;
493 }
494
495 void HereView::__processViewObject(maps_view_h view, const maps_view_object_h object, maps_view_object_operation_e operation)
496 {
497         HereView *hv = NULL;
498         int maps_error = maps_view_get_maps_plugin_view_handle(view, (void**)&hv);
499         if (maps_error != MAPS_ERROR_NONE || !hv) return;
500
501         maps_view_object_type_e type;
502         maps_view_object_get_type(object, &type);
503
504         if (type < MAPS_VIEW_OBJECT_POLYLINE || type > MAPS_VIEW_OBJECT_MARKER) return;
505         if (operation < MAPS_VIEW_OBJECT_ADD || operation > MAPS_VIEW_OBJECT_REMOVE) return;
506
507         const char *oper_str[20] = { "ADD", "SET_VISIBLE", "MOVE", "CHANGE", "REMOVE"};
508         const char *type_str[20] = { "POLYLINE", "POLYGON", "MARKER", "ROUTE", "UNKNOWN"};
509
510         MAPS_LOGD("type=%s, operation=%s, object=%p",
511                 (type >= MAPS_VIEW_OBJECT_POLYLINE && type <= MAPS_VIEW_OBJECT_MARKER) ? type_str[type] : "?",
512                 (operation >= MAPS_VIEW_OBJECT_ADD && operation <= MAPS_VIEW_OBJECT_REMOVE) ? oper_str[operation] : "?",
513                 object);
514
515         switch(operation)
516         {
517         case MAPS_VIEW_OBJECT_ADD:                              hv->__visualObjects.add(object); break;
518         case MAPS_VIEW_OBJECT_SET_VISIBLE:              hv->__visualObjects.setVisible(object); break;
519         case MAPS_VIEW_OBJECT_CHANGE:                   hv->__visualObjects.update(object); break;
520         case MAPS_VIEW_OBJECT_REMOVE:                   hv->__visualObjects.remove(object); break;
521         default:                        break;
522         }
523 }
524
525 here_error_e HereView::captureSnapshot(maps_view_h view, void **data, int *width, int *height,
526         maps_view_colorspace_type_e *cs)
527 {
528         if (!__isInitialized || !__map || __w <= 0 || __h <= 0)
529                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
530
531         int sizeOfLine = (__w * 4);
532         unsigned char *readData = (unsigned char*)malloc(sizeOfLine * __h);
533         if (!readData)
534                 return HERE_ERROR_OUT_OF_MEMORY;
535
536         *data = (void*)malloc(sizeOfLine * __h);
537         if (!*data) {
538                 free(readData);
539                 return HERE_ERROR_OUT_OF_MEMORY;
540         }
541
542         __pixelGetCb(view, NULL);
543         __api->glReadPixels(0, 0, __w, __h, GL_RGBA, GL_UNSIGNED_BYTE, readData);
544         for(int i = 0; i < __h; i++)
545                 memcpy((unsigned char*)*data + sizeOfLine * i, readData + sizeOfLine * (__h - i - 1), sizeOfLine);
546         free(readData);
547
548         *width = __w;
549         *height = __h;
550         *cs = MAPS_VIEW_COLORSPACE_RGBA8888;
551
552         return HERE_ERROR_NONE;
553 }
554
555 here_error_e HereView::getViewScale(maps_view_h view, double *scale)
556 {
557         if (!view || !scale)
558                 return HERE_ERROR_INVALID_PARAMETER;
559
560         if (!__isInitialized || !__map)
561                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
562
563         *scale = __map->GetScale();
564
565         return HERE_ERROR_NONE;
566 }
567
568 here_error_e HereView::setViewScale(maps_view_h view, double scale)
569 {
570         if (!view)
571                 return HERE_ERROR_INVALID_PARAMETER;
572
573         if (!__isInitialized || !__map)
574                 return HERE_ERROR_SERVICE_NOT_AVAILABLE;
575
576         __map->SetScale(scale);
577
578         return HERE_ERROR_NONE;
579 }
580
581 HERE_PLUGIN_END_NAMESPACE