Maps Deadlock Issue Fix
[platform/core/location/maps-plugin-here.git] / src / here_view_objects.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_objects.h"
18 #include "here_utils.h"
19
20 #include <graphic/Grp_Util.h>
21 #include <maps/GeoMapObjectMarker.h>
22 #include <maps/GeoMapObjectPolygon.h>
23 #include <maps/GeoMapObjectPolyline.h>
24
25
26 using namespace HERE_PLUGIN_NAMESPACE_PREFIX;
27
28 HERE_PLUGIN_BEGIN_NAMESPACE
29
30 HereViewObjects::HereViewObjects()
31 {
32         __map = NULL;
33         __evas = NULL;
34         pthread_mutex_init(&__mutex, NULL);
35 }
36
37 HereViewObjects::~HereViewObjects()
38 {
39         pthread_mutex_destroy(&__mutex);
40 }
41
42 void HereViewObjects::set(GeoTiledMap *map, Evas *evas)
43 {
44         if (!map && !evas) removeAll();
45         __map = map;
46         __evas = evas;
47 }
48
49 here_error_e HereViewObjects::add(maps_view_object_h hObj)
50 {
51         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
52
53         here_error_e error = HERE_ERROR_INVALID_PARAMETER;
54         if (__currentObjects.find(hObj) == __currentObjects.end())
55                 error = __add(hObj);
56
57         if (error == HERE_ERROR_NONE) __invalidate(hObj);
58         return error;
59 }
60
61 here_error_e HereViewObjects::__add(maps_view_object_h hObj)
62 {
63         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
64         if (!__map) return HERE_ERROR_INVALID_OPERATION;
65
66         here_error_e error = HERE_ERROR_NONE;
67         GeoMapObject *hereObject = NULL;
68         maps_view_object_type_e type;
69         maps_view_object_get_type(hObj, &type);
70
71         switch(type) {
72         case MAPS_VIEW_OBJECT_MARKER:
73                 hereObject = new (std::nothrow) GeoMapObjectMarker;
74                 error = __updateMarker(hObj, (GeoMapObjectMarker*)hereObject);
75                 break;
76
77         case MAPS_VIEW_OBJECT_POLYGON:
78                 hereObject = new (std::nothrow) GeoMapObjectPolygon;
79                 error = __updatePolygon(hObj, (GeoMapObjectPolygon*)hereObject);
80                 break;
81
82         case MAPS_VIEW_OBJECT_POLYLINE:
83                 hereObject = new (std::nothrow) GeoMapObjectPolyline;
84                 error = __updatePolyline(hObj, (GeoMapObjectPolyline*)hereObject);
85                 break;
86 #ifdef TIZEN_3_0_NEXT_MS
87         case MAPS_VIEW_OBJECT_ROUTE:
88                 for (int i=0; i < 2; i++) {
89                         hereObject = new (std::nothrow) GeoMapObjectPolyline;
90                         if (hereObject) {
91                                 __map->AddObject(hereObject);
92                                 error = __updateRoute(hObj);
93                                 if (error != HERE_ERROR_NONE) break;
94                                 pthread_mutex_lock(&__mutex);
95                                 __currentObjects.insert(std::make_pair(hObj, (GeoMapObjectPolyline*)hereObject));
96                                 pthread_mutex_unlock(&__mutex);
97                         }
98
99                         hereObject = new (std::nothrow) GeoMapObjectMarker;
100                         if (hereObject) {
101                                 __map->AddObject(hereObject);
102                                 error = __updateRoute(hObj);
103                                 if (error != HERE_ERROR_NONE) break;
104                                 pthread_mutex_lock(&__mutex);
105                                 __currentObjects.insert(std::make_pair(hObj, (GeoMapObjectMarker*)hereObject));
106                                 pthread_mutex_unlock(&__mutex);
107                         }
108                 }
109                 break;
110 #endif /* TIZEN_3_0_NEXT_MS */
111         default:
112                 error = HERE_ERROR_INVALID_PARAMETER;
113                 break;
114         }
115
116         if (error != HERE_ERROR_NONE) {
117                 if (hereObject) delete hereObject;
118                 hereObject = NULL;
119         }
120
121         if (hereObject
122 #ifdef TIZEN_3_0_NEXT_MS
123                 && type != MAPS_VIEW_OBJECT_ROUTE
124 #endif /* TIZEN_3_0_NEXT_MS */
125         ) {
126                 __map->AddObject(hereObject);
127                 pthread_mutex_lock(&__mutex);
128                 __currentObjects.insert(std::make_pair(hObj, hereObject));
129                 pthread_mutex_unlock(&__mutex);
130         }
131
132         return error;
133 }
134
135 here_error_e HereViewObjects::remove(maps_view_object_h hObj)
136 {
137         here_error_e error = __remove(hObj);
138         if (error == HERE_ERROR_NONE) __invalidate(hObj);
139         return error;
140 }
141
142 here_error_e HereViewObjects::__remove(maps_view_object_h hObj)
143 {
144         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
145         if (!__map) return HERE_ERROR_INVALID_OPERATION;
146
147         here_error_e error = HERE_ERROR_NOT_FOUND;
148
149         VisualObjects::iterator it;
150         pthread_mutex_lock(&__mutex);
151         while ((it = __currentObjects.find(hObj)) != __currentObjects.end()) {
152                 __map->RemoveObject((GeoMapObject*)it->second);
153                 it = __currentObjects.erase(it);
154                 error = HERE_ERROR_NONE;
155         }
156         pthread_mutex_unlock(&__mutex);
157
158         return error;
159 }
160
161 here_error_e HereViewObjects::removeAll()
162 {
163         pthread_mutex_lock(&__mutex);
164         __currentObjects.clear();
165         __map->ClearMapObjects();
166         pthread_mutex_unlock(&__mutex);
167         __invalidate();
168
169         return HERE_ERROR_NONE;
170 }
171
172 here_error_e HereViewObjects::move(maps_view_object_h hObj)
173 {
174         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
175
176         VisualObjects::iterator it;
177         while ((it = __currentObjects.find(hObj)) != __currentObjects.end())
178                 MAPS_LOGD("TODO: implement moving");
179
180         return HERE_ERROR_NONE;
181 }
182
183 here_error_e HereViewObjects::update(maps_view_object_h hObj)
184 {
185         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
186
187         here_error_e error = HERE_ERROR_NOT_FOUND;
188
189         VisualObjects::iterator it = __currentObjects.find(hObj);
190         if (it != __currentObjects.end())
191                 error = __update(hObj, (GeoMapObject*)(it->second));
192
193         if (error == HERE_ERROR_NONE) __invalidate(hObj);
194         return error;
195 }
196
197 here_error_e HereViewObjects::__update(maps_view_object_h hObj, GeoMapObject *hereObject)
198 {
199         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
200
201         here_error_e error = HERE_ERROR_UNKNOWN;
202
203         do {
204                 maps_view_object_type_e type;
205                 maps_view_object_get_type(hObj, &type);
206
207                 switch(type) {
208                 case MAPS_VIEW_OBJECT_MARKER:
209                         error = __updateMarker(hObj, (GeoMapObjectMarker*)hereObject);
210                         break;
211
212                 case MAPS_VIEW_OBJECT_POLYGON:
213                         error = __updatePolygon(hObj, (GeoMapObjectPolygon*)hereObject);
214                         break;
215
216                 case MAPS_VIEW_OBJECT_POLYLINE:
217                         error = __updatePolyline(hObj, (GeoMapObjectPolyline*)hereObject);
218                         break;
219
220 #ifdef TIZEN_3_0_NEXT_MS
221                 case MAPS_VIEW_OBJECT_ROUTE:
222                         error = __updateRoute(hObj);
223                         break;
224 #endif /* TIZEN_3_0_NEXT_MS */
225
226                 default:
227                         break;
228                 }
229         } while (0);
230
231         return error;
232 }
233
234 here_error_e HereViewObjects::__updateMarker(maps_view_object_h hMarker, GeoMapObjectMarker *hereMarker)
235 {
236         if (!hMarker || !hereMarker)
237                 return HERE_ERROR_INVALID_PARAMETER;
238
239         if (!__evas || !__map)
240                 return HERE_ERROR_INVALID_OPERATION;
241
242
243         int error = MAPS_ERROR_NONE;
244         maps_view_marker_type_e type;
245         int nSize = 0, w, h;
246         char *szPath = NULL;
247         double lat, lng;
248         maps_coordinates_h mapsCoord;
249         Evas_Object *img = NULL;
250
251
252         do {
253                 /* image */
254                 error = maps_view_object_marker_get_type(hMarker, &type);
255                 if (error != MAPS_ERROR_NONE || type < MAPS_VIEW_MARKER_PIN || type > MAPS_VIEW_MARKER_STICKER) break;
256
257                 error = maps_view_object_marker_get_image_file(hMarker, &szPath);
258                 if (error != MAPS_ERROR_NONE || !szPath) break;
259
260                 img = evas_object_image_add(__evas);
261                 evas_object_image_file_set(img, szPath, NULL);
262                 int err = evas_object_image_load_error_get(img);
263
264                 if (err != EVAS_LOAD_ERROR_NONE) {
265                         MAPS_LOGE("Failed to load the image file for new marker. '%s'",
266                                 (szPath ? szPath : "null"));
267                         g_free(szPath);
268                         break;
269                 }
270                 g_free(szPath);
271
272                 evas_object_image_size_get(img, &w, &h);
273                 nSize = w * h * 4;
274
275                 unsigned char *src = (unsigned char*)evas_object_image_data_get(img, EINA_FALSE);
276                 if (!src || nSize <= 0) {
277                         MAPS_LOGE("Failed to get the image buffer of new marker");
278                         error = MAPS_ERROR_OUT_OF_MEMORY;
279                         break;
280                 }
281
282                 unsigned char *dst = (unsigned char*)malloc(nSize);
283                 if (!dst) {
284                         error = MAPS_ERROR_OUT_OF_MEMORY;
285                         break;
286                 }
287                 memcpy(dst, src, nSize);
288
289                 /* resize the marker image */
290                 int nw = 0, nh = 0;
291                 if (__resizeMarker(hMarker, w, h, &nw, &nh, &dst)) {
292                         w = nw;
293                         h = nh;
294                         nSize = w * h * 4;
295                 }
296                 maps_view_object_marker_set_size(hMarker, w, h);
297
298                 /* convert RGBA to BGRA for GL */
299                 _Util::ConvertRGBA2BGRA(dst, (unsigned)w, (unsigned)h);
300
301                 Bitmap bmp;
302                 if (bmp.Construct((const unsigned char*)dst, nSize, Dimension(w, h)) != 0) {
303                         MAPS_LOGE("Failed to construct a bitmap object");
304                         error = MAPS_ERROR_INVALID_OPERATION;
305                         free(dst);
306                         break;
307                 }
308                 hereMarker->SetBitmap(bmp);
309                 free(dst);
310
311
312                 /* position */
313                 maps_view_object_marker_get_coordinates(hMarker, &mapsCoord);
314                 maps_coordinates_get_latitude(mapsCoord, &lat);
315                 maps_coordinates_get_longitude(mapsCoord, &lng);
316                 maps_coordinates_destroy(mapsCoord);
317
318                 if (!HereUtils::IsValidCoord(lat, lng)) {
319                         error = MAPS_ERROR_INVALID_PARAMETER;
320                         break;
321                 }
322
323                 hereMarker->SetPosition(GeoCoordinates(lat, lng));
324
325                 /* origin */
326                 Tizen::Maps::FloatPoint fpntOrigin(0.5, 0.5);
327                 if (type == MAPS_VIEW_MARKER_PIN)
328                         fpntOrigin.y = 1.0;
329                 hereMarker->SetMarkerOrigin(fpntOrigin);
330
331                 /* z-order */
332                 int z_order = 0;
333                 maps_view_object_marker_get_z_order(hMarker, &z_order);
334                 hereMarker->SetZOrder(z_order);
335         } while (0);
336
337         if (img) evas_object_del(img);
338         return (here_error_e)ConvertToHereError(error);
339 }
340
341 here_error_e HereViewObjects::__updatePolyline(maps_view_object_h hPolyline, GeoMapObjectPolyline *herePolyline)
342 {
343         if (!hPolyline || !herePolyline)
344                 return HERE_ERROR_INVALID_PARAMETER;
345
346         int error = MAPS_ERROR_NONE;
347         GeoCoordinateList coordList;
348         unsigned char r, g, b, a;
349         int nThickness;
350
351         do {
352                 error = maps_view_object_polyline_foreach_point(hPolyline, __foreachForCoordinates, &coordList);
353                 if (error != MAPS_ERROR_NONE) break;
354                 herePolyline->SetPath(coordList);
355
356                 error = maps_view_object_polyline_get_color(hPolyline, &r, &g, &b, &a);
357                 if (error != MAPS_ERROR_NONE) break;
358                 herePolyline->SetStrokeColor(Color(r, g, b, a));
359
360                 error = maps_view_object_polyline_get_width(hPolyline, &nThickness);
361                 if (error != MAPS_ERROR_NONE) break;
362                 herePolyline->SetStrokeThickness(nThickness);
363         } while (0);
364
365         return (here_error_e)ConvertToHereError(error);
366 }
367
368 here_error_e HereViewObjects::__updatePolygon(maps_view_object_h hPolygon, GeoMapObjectPolygon *herePolygon)
369 {
370         if (!hPolygon || !herePolygon)
371                 return HERE_ERROR_INVALID_PARAMETER;
372
373         int error = MAPS_ERROR_NONE;
374         GeoCoordinateList coordList;
375         unsigned char r, g, b, a;
376
377         do {
378                 error = maps_view_object_polygon_foreach_point(hPolygon, __foreachForCoordinates, &coordList);
379                 if (error != MAPS_ERROR_NONE) break;
380                 herePolygon->SetPath(coordList);
381
382                 error = maps_view_object_polygon_get_fill_color(hPolygon, &r, &g, &b, &a);
383                 if (error != MAPS_ERROR_NONE) break;
384                 herePolygon->SetFillColor(Color(r, g, b, a));
385         } while (0);
386
387         return (here_error_e)ConvertToHereError(error);
388 }
389
390 here_error_e HereViewObjects::__updateRoute(maps_view_object_h hRoute)
391 {
392 #ifdef TIZEN_3_0_NEXT_MS
393         if (!hRoute) return HERE_ERROR_INVALID_PARAMETER;
394
395         VisualObjects::iterator it;
396
397         if ((it = __currentObjects.find(hRoute)) != __currentObjects.end()) {
398                 maps_route_h route = NULL;
399                 int ret = maps_view_object_route_get_content(hRoute, &route);
400                 if (ret !=  MAPS_ERROR_NONE || !route)
401                         return HERE_ERROR_NONE;
402
403                 GeoCoordinateList coordList;
404                 GeoMapObjectPolyline *polyline_path = NULL, *polyline_seg = NULL;
405
406                 if (it->second->GetType() == GeoMapObject::GMO_Polyline) {
407                         if (!polyline_path) {
408                                 MAPS_LOGD("Route Path");
409                                 polyline_path = (GeoMapObjectPolyline*)it->second;
410                                 maps_route_foreach_path(route, __foreachForCoordinates, &coordList);
411                                 polyline_path->SetPath(coordList);
412                                 polyline_path->SetStrokeColor(Tizen::Maps::Color(255, 0, 0, 255));
413                                 polyline_path->SetStrokeThickness(3);
414                         } else if (!polyline_seg) {
415                                 MAPS_LOGD("Route Segments");
416                                 polyline_seg = (GeoMapObjectPolyline*)it->second;
417                                 maps_route_foreach_path(route, __foreachForCoordinates, &coordList);
418                                 polyline_seg->SetPath(coordList);
419                                 polyline_seg->SetStrokeColor(Tizen::Maps::Color(0, 255, 0, 255));
420                                 polyline_seg->SetStrokeThickness(3);
421                         }
422                 } else if (it->second->GetType() == GeoMapObject::GMO_Marker) {
423                         // to implement
424                 }
425                 maps_route_destroy(route);
426         }
427
428 #endif /* TIZEN_3_0_NEXT_MS */
429         return HERE_ERROR_NONE;
430 }
431
432 here_error_e HereViewObjects::setVisible(maps_view_object_h hObj)
433 {
434         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
435
436         bool visible;
437         maps_view_object_get_visible(hObj, &visible);
438         return __setVisible(hObj, visible);
439 }
440
441 here_error_e HereViewObjects::__setVisible(maps_view_object_h hObj, bool bVisible)
442 {
443         if (!hObj) return HERE_ERROR_INVALID_PARAMETER;
444
445         here_error_e error = HERE_ERROR_NOT_FOUND;
446
447         VisualObjects::iterator it;
448         for (it = __currentObjects.begin(); it != __currentObjects.end(); it++) {
449                 if (it->first == hObj) {
450                         ((GeoMapObject*)it->second)->SetVisible(bVisible);
451                         error = HERE_ERROR_NONE;
452                 }
453         }
454
455         if (error == HERE_ERROR_NONE) __invalidate(hObj);
456         return error;
457 }
458
459 bool HereViewObjects::__foreachForCoordinates(int index, maps_coordinates_h point, void *user_data)
460 {
461         if (!point || !user_data)
462                 return false;
463
464         if (!HereUtils::IsValid(*(maps_coordinates_s*)point))
465                 return false;
466
467         int error;
468         double lat = 0.0, lng = 0.0;
469
470         do {
471                 error = maps_coordinates_get_latitude(point, &lat);
472                 if (error != MAPS_ERROR_NONE) break;
473
474                 error = maps_coordinates_get_longitude(point, &lng);
475                 if (error != MAPS_ERROR_NONE) break;
476         } while (0);
477
478         MAPS_LOGD("[%d] %f,%f", index+1, lat, lng);
479
480         GeoCoordinateList *coordList = (GeoCoordinateList*)user_data;
481         coordList->push_back(GeoCoordinates(lat, lng));
482         return true;
483 }
484
485 bool HereViewObjects::__foreachForAddingGroupObjects(int index, int total, maps_view_object_h object, void *user_data)
486 {
487         if (!user_data) return false;
488
489         HereViewObjects *hereViewObjects = (HereViewObjects*)user_data;
490         here_error_e error = hereViewObjects->add(object);
491         return (error == HERE_ERROR_NONE);
492 }
493
494 bool HereViewObjects::__foreachForRemovingGroupObjects(int index, int total, maps_view_object_h object, void *user_data)
495 {
496         if (!user_data) return false;
497
498         HereViewObjects *hereViewObjects = (HereViewObjects*)user_data;
499         here_error_e error = hereViewObjects->remove(object);
500         return (error == HERE_ERROR_NONE);
501 }
502
503 bool HereViewObjects::__foreachForUpdatingGroupObjects(int index, int total, maps_view_object_h object, void *user_data)
504 {
505         if (!user_data) return false;
506
507         HereViewObjects *hereViewObjects = (HereViewObjects*)user_data;
508         here_error_e error = hereViewObjects->update(object);
509         return (error == HERE_ERROR_NONE);
510 }
511
512 bool HereViewObjects::__foreachForSettingVisibleGroupObjects(int index, int total, maps_view_object_h object, void *user_data)
513 {
514         if (!user_data) return false;
515
516         HereViewObjects *hereViewObjects = (HereViewObjects*)user_data;
517         here_error_e error = hereViewObjects->setVisible(object);
518         return (error == HERE_ERROR_NONE);
519 }
520
521 bool HereViewObjects::__resizeMarker(maps_view_object_h hMarker,
522                                         const int originWidth, const int originHeight,
523                                         int *newWidth, int *newHeight, unsigned char **bitmap)
524 {
525         if (!hMarker || !newWidth || !newHeight || !bitmap || !*bitmap)
526                 return false;
527
528         int resizedWidth = 0, resizedHeight = 0;
529         maps_view_object_marker_get_size(hMarker, &resizedWidth, &resizedHeight);
530
531         /* Set the size proportionally if one of new sizes is zero. */
532         if (resizedWidth == 0 && resizedHeight > 0)
533                 resizedWidth = resizedHeight * (originWidth / originHeight);
534         else if (resizedHeight == 0 && resizedWidth > 0)
535                 resizedHeight = resizedWidth * (originHeight / originWidth);
536
537         if (__resizeBitmap(bitmap, originWidth, originHeight, resizedWidth, resizedHeight)) {
538                 *newWidth = resizedWidth;
539                 *newHeight = resizedHeight;
540                 return true;
541         }
542         return false;
543 }
544
545 bool HereViewObjects::__resizeBitmap(unsigned char **curBmp, int curWidth, int curHeight, int newWidth, int newHeight)
546 {
547         if (!curBmp || curWidth <= 0 || curHeight <= 0 || newWidth <= 0 || newHeight <= 0) return false;
548         if (curWidth == newWidth && curHeight == newHeight) return false;
549
550         unsigned char *newBmp = (unsigned char*)malloc(newWidth * newHeight * 4);
551         if(!newBmp) {
552                 MAPS_LOGD("malloc failed for newBmp");
553                 return false;
554         }
555
556         double scaleWidth =  (double)newWidth / (double)curWidth;
557         double scaleHeight = (double)newHeight / (double)curHeight;
558
559         int newPixel, curPixel;
560
561         for (int y = 0; y < newHeight; y++) {
562             for (int x = 0; x < newWidth; x++) {
563                 newPixel = (y * (newWidth *4)) + (x * 4);
564                 curPixel = (((int)(y / scaleHeight) * (curWidth * 4)) + ((int)(x / scaleWidth) * 4));
565
566                 newBmp[newPixel    ] =  (*curBmp)[curPixel    ];
567                 newBmp[newPixel + 1] =  (*curBmp)[curPixel + 1];
568                 newBmp[newPixel + 2] =  (*curBmp)[curPixel + 2];
569                 newBmp[newPixel + 3] =  (*curBmp)[curPixel + 3];
570             }
571         }
572
573         g_free(*curBmp);
574         *curBmp = newBmp;
575         return true;
576 }
577
578 void HereViewObjects::__invalidate(maps_view_object_h hObj)
579 {
580         maps_view_object_type_e type;
581         maps_view_object_get_type(hObj, &type);
582
583         if (!hObj || type != MAPS_VIEW_OBJECT_MARKER)
584                 __map->InvalidateMapObjects();
585         else
586                 __map->InvalidateMapMarkers();
587 }
588
589 HERE_PLUGIN_END_NAMESPACE