1. Changed license year
[apps/home/mobileprint.git] / mobileprint / preview_engine / lib / preview_task_model.c
1 /*
2 *  Mobileprint
3 *
4 * Copyright 2013  Samsung Electronics Co., Ltd
5
6 * Licensed under the Flora License, Version 1.1 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9
10 * http://floralicense.org/license/
11
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20 #include <Ecore.h>
21
22 #include <page_preview.h>
23 #include <pdfgen.h>
24 #include <preview_coords.h>
25 #include <previewgen.h>
26
27 #include "pts_debug.h"
28
29 #include "preview_task_model.h"
30
31
32 #define PREVIEWGEN_EXECUTABLE   BINDIR "/previewgen-tool"
33 #define SHADOW_SIZE_PX_X 10
34 #define SHADOW_SIZE_PX_Y 10
35
36 #define CMD_STR_MAX_LEN         1024
37
38 #define SINGLE_PAGE_PREVIEWGEN
39
40
41 /* TODO: task model destruction */
42 enum preview_task_type {
43         PREVIEW_TASK_EMPTY_PAGE,
44         PREVIEW_TASK_GENERIC,
45         PREVIEW_TASK_INITIAL
46 };
47
48
49 struct preview_task_data {
50         int page;
51         enum preview_task_type task_type;
52         struct preview_conf conf;
53         char out_pic_fname[sizeof(PREVIEW_TEMP_DIR "/mobileprint_xxxx.ppm ")];
54         enum file_type ftype;
55         int is_task_ok;
56
57         struct preview_model *pmodel;
58         struct preview_task_model *task_model;
59         char *previewgen_exe_cmd;
60 };
61
62
63 int init_preview_task_model(struct preview_task_model *model,
64                                                         struct preview_engine *engine)
65 {
66         PTS_TRACE_BEGIN;
67         PTS_RETV_IF(model == NULL || engine == NULL, -1 , "Invalid argument");
68
69         /*model->task_count = MAX_PREVIEW_TASK_COUNT;
70         model->tasks = malloc(sizeof(struct preview_task) * model->task_count);
71         if (NULL == model->tasks) {
72                 model->task_count = 0;
73                 return -1;
74         }*/
75         model->task_list = NULL;
76         model->previewgen_handle = NULL;
77         model->event_handler = NULL;
78         model->is_stop_processing = 0;
79         model->engine = engine;
80
81         //model->pdata = pdata;
82         PTS_TRACE_END;
83         return 0;
84 }
85
86
87 int clear_preview_task_queue(struct preview_task_model *task_model)
88 {
89         PTS_TRACE_BEGIN;
90         PTS_RETV_IF(task_model == NULL , -1 , "Invalid argument");
91
92         struct preview_task_data *ptd;
93         Eina_List *cur;
94
95         if (task_model->task_list != NULL) {
96                 /* clean task list */
97                 EINA_LIST_FOREACH(task_model->task_list, cur, ptd) {
98                         PTS_IF_FREE_MEM(ptd);
99                 }
100                 eina_list_free(task_model->task_list);
101         }
102         task_model->task_list = NULL;
103         PTS_TRACE_END;
104         return 0;
105 }
106
107
108 int parse_previewgen_output(Ecore_Exe_Event_Data *data_from_process,
109                 enum file_type ftype, int *pages_count)
110 {
111         PTS_TRACE_BEGIN;
112         PTS_RETV_IF(NULL == pages_count || NULL == data_from_process
113                         || data_from_process->size <= 0,
114                         -1, "Invalid argument");
115         PTS_DEBUG("data_from_process->size : %d\n", data_from_process->size);
116         char *msg = calloc(1, data_from_process->size + 1);
117         PTS_RETV_IF(NULL == msg, -1, "Memory allocation error");
118
119         strncpy(msg, data_from_process->data, data_from_process->size);
120         msg[data_from_process->size] = '\0';
121         *pages_count = 0;
122
123         PTS_DEBUG("msg: %s", msg);
124
125         switch (ftype) {
126         case FILE_TYPE_IMAGE:
127                 sscanf(msg, "init img: pages count: %d", pages_count);
128                 break;
129         case FILE_TYPE_PDF:
130                 sscanf(msg, "init pdf: pages count: %d", pages_count);
131                 break;
132         case FILE_TYPE_INCORRECT:
133                 *pages_count = 0;
134                 break;
135         }
136         PTS_IF_FREE_MEM(msg);
137         PTS_TRACE_END;
138         PTS_RETV_IF (*pages_count <= 0, -1, "Error");
139         return 0;
140 }
141
142
143 static Eina_Bool preview_handler_end_cb(void *d, int type, void *event)
144 {
145         PTS_TRACE_BEGIN;
146
147         PTS_RETV_IF(d == NULL, ECORE_CALLBACK_DONE, "Invalid argument");
148
149         struct preview_task_data *ptd = (struct preview_task_data *)d;
150         struct preview_task_data *next_ptd;
151         struct preview_task_model *task_model = ptd->task_model;
152         int is_init_engine = 1;
153         int res;
154
155         /* TODO: check for next initialization in queue */
156
157         switch (ptd->task_type) {
158         case PREVIEW_TASK_EMPTY_PAGE:
159                 preview_model_page_available(ptd->pmodel,
160                                 PREVIEW_ENGINE_EVENT_EMPTY_PAGE_READY,
161                                 0);
162                 break;
163         case PREVIEW_TASK_GENERIC:
164                 /* TODO: check does task OK (parse output) */
165                 //if (ptd->is_task_ok) {
166                         preview_model_page_available(ptd->pmodel,
167                                         PREVIEW_ENGINE_EVENT_PAGE_READY,
168                                         ptd->page);
169                 /*} else {
170                         preview_model_page_available(ptd->pmodel,
171                                         PREVIEW_ENGINE_EVENT_PAGE_ERROR,
172                                         ptd->page);
173                 }*/
174                 break;
175         case PREVIEW_TASK_INITIAL:
176                 if (task_model->task_list != NULL) {
177                         next_ptd = (struct preview_task_data *)
178                                 eina_list_data_get(task_model->task_list);
179                         if (PREVIEW_TASK_INITIAL == next_ptd->task_type) {
180                                 is_init_engine = 0;
181                         }
182                 }
183                 if (is_init_engine) {
184                         res = parse_previewgen_output(
185                                         (Ecore_Exe_Event_Data *)event,
186                                         ptd->ftype,
187                                         &(ptd->conf.pages_count));
188                         if (res >= 0)
189                                 preview_engine_init_done(task_model->engine,
190                                                         &(ptd->conf));
191                         /* TODO: ERROR condition in case of res < 0 */
192                 }
193                 PTS_DEBUG("releasing memory");
194                 destroy_preview_conf(&(ptd->conf));
195                 PTS_DEBUG("memory released");
196                 break;
197         }
198
199         task_model->previewgen_handle = NULL;
200         ecore_event_handler_del(task_model->event_handler);
201         task_model->event_handler = NULL;
202         PTS_DEBUG("Freeing memory");
203         PTS_IF_FREE_MEM(ptd->previewgen_exe_cmd);
204         PTS_IF_FREE_MEM(ptd);
205
206         /* manage tasks queue */
207         if (task_model->task_list != NULL) {
208                 ptd = (struct preview_task_data *)
209                           eina_list_data_get(task_model->task_list);
210                 task_model->task_list = eina_list_remove_list(
211                                 task_model->task_list, task_model->task_list);
212                 task_model->previewgen_handle =
213                         ecore_exe_pipe_run(ptd->previewgen_exe_cmd,
214                                         ECORE_EXE_PIPE_READ_LINE_BUFFERED
215                                         | ECORE_EXE_PIPE_READ, NULL);
216                 if (NULL == task_model->previewgen_handle) {
217                         PTS_DEBUG("ecore_exe_pipe_run error (%s)",
218                                         ptd->previewgen_exe_cmd);
219                         PTS_IF_FREE_MEM(ptd->previewgen_exe_cmd);
220                         PTS_IF_FREE_MEM(ptd);
221                         PTS_TRACE_END;
222                         return ECORE_CALLBACK_DONE;
223                 }
224                 task_model->event_handler = ecore_event_handler_add(
225                                 ECORE_EXE_EVENT_DATA,
226                                 preview_handler_end_cb, ptd);
227         }
228
229         PTS_TRACE_END;
230         return ECORE_CALLBACK_DONE;
231 }
232
233
234 int add_preview_task_initial(struct preview_task_model *model,
235                                  const struct preview_conf *conf)
236 {
237         PTS_TRACE_BEGIN;
238         PTS_RETV_IF(model == NULL || conf == NULL, -1, "Invalid argument");
239
240         char *fnames_str;
241         struct preview_task_data *ptd;
242         int i;
243         int fnames_strlen;
244
245         /* fill the preview_task_data structure */
246         ptd = malloc(sizeof(struct preview_task_data));
247         PTS_RETV_IF(ptd == NULL, -1, "malloc failed");
248
249         memset(ptd, 0, sizeof(struct preview_task_data));
250         ptd->task_type = PREVIEW_TASK_INITIAL;
251         ptd->conf = *conf;
252         ptd->task_model = model;
253         /* fill cmd with arguments from ptd depending on file type*/
254         /* TODO: check for each file */
255         ptd->ftype = get_file_type(ptd->conf.initial_fnames[0]);
256
257         ptd->previewgen_exe_cmd = NULL;
258
259         enum page_scale_type scale_type = ptd->conf.scale.type;
260         switch (ptd->ftype) {
261         case FILE_TYPE_IMAGE:
262                 /* calculate correct string length to support
263                    many images*/
264                 fnames_strlen = 0;
265                 for (i = 0; i < conf->files_count; ++i)
266                         fnames_strlen += strlen(ptd->conf.initial_fnames[i])
267                                         + 1;
268                 fnames_str = (char*)malloc(sizeof(char) * (fnames_strlen + 1));
269                 if (NULL == fnames_str) {
270                         PTS_IF_FREE_MEM(ptd);
271                         PTS_RETV_IF(ptd == NULL, -1, "malloc failed");
272                 }
273                 /* generate fnames list string */
274                 fnames_str[0] = '\0';
275                 for (i = 0; i < conf->files_count; ++i) {
276                         strncat(fnames_str, ptd->conf.initial_fnames[i],
277                                         fnames_strlen);
278                         strncat(fnames_str, " ", fnames_strlen);
279                 }
280                 fnames_str[fnames_strlen] = '\0';
281                 /* generate command string */
282                 ptd->previewgen_exe_cmd = (char*)malloc(sizeof(char)
283                                 * (CMD_STR_MAX_LEN + fnames_strlen + 1));
284                 if (NULL == ptd->previewgen_exe_cmd) {
285                         PTS_IF_FREE_MEM(ptd);
286                         PTS_IF_FREE_MEM(fnames_str);
287                         PTS_RETV_IF(ptd == NULL, -1, "malloc failed");
288                 }
289                 PTS_DEBUG("processing image");
290                 snprintf(ptd->previewgen_exe_cmd, CMD_STR_MAX_LEN,
291                                 PREVIEWGEN_EXECUTABLE " init img "
292                                 "%s%s %s %s %lf %lf %d %d %s %d %s %d %lf %lf %d",
293                                 fnames_str, ptd->conf.fname,
294                                 ptd->conf.ppd, ptd->conf.paper_size.name,
295                                 ptd->conf.paper_size.s.x, ptd->conf.paper_size.s.y,
296                                 ptd->conf.settings_req.available_size_px.x,
297                                 ptd->conf.settings_req.available_size_px.y,
298                                 (PAGE_ORIENTATION_LANDSCAPE == ptd->conf.orientation)
299                                         ? "landscape" :
300                                 (PAGE_ORIENTATION_PORTRAIT == ptd->conf.orientation)
301                                         ? "portrait" : "",
302                                 ptd->conf.n_up,
303                                 (SCALE_FIT_TO_PAPER == scale_type) ? "fit_to_paper" :
304                                 (SCALE_CUSTOM == scale_type) ? "custom" :
305                                 (SCALE_RELATIVE == scale_type) ? "relative" :
306                                 (SCALE_ORIGINAL == scale_type) ? "original" : "",
307                                 ptd->conf.scale.zoom, ptd->conf.scale.w, ptd->conf.scale.h,
308                                 ptd->conf.settings_req.is_grayscale);
309                 PTS_IF_FREE_MEM(fnames_str);
310                 PTS_DEBUG("cmd: %s", ptd->previewgen_exe_cmd);
311                 break;
312         case FILE_TYPE_PDF:
313                 PTS_DEBUG("processing PDF");
314                 ptd->previewgen_exe_cmd = malloc(sizeof(char)
315                                 * (CMD_STR_MAX_LEN + 1));
316                 snprintf(ptd->previewgen_exe_cmd, CMD_STR_MAX_LEN,
317                          PREVIEWGEN_EXECUTABLE " init pdf "
318                          "%s %s %s %s %lf %lf %s %d %s %d %lf %lf %d",
319                          ptd->conf.initial_fnames[0], ptd->conf.fname,
320                          ptd->conf.ppd, ptd->conf.paper_size.name,
321                          ptd->conf.paper_size.s.x, ptd->conf.paper_size.s.y,
322                          (PAGE_ORIENTATION_LANDSCAPE == ptd->conf.orientation) ? "landscape" :
323                          (PAGE_ORIENTATION_PORTRAIT == ptd->conf.orientation) ? "portrait" : "",
324                          ptd->conf.n_up,
325                          (SCALE_FIT_TO_PAPER == scale_type) ? "fit_to_paper" :
326                          (SCALE_CUSTOM == scale_type) ? "custom" :
327                          (SCALE_RELATIVE == scale_type) ? "relative" :
328                          (SCALE_ORIGINAL == scale_type) ? "original" : "",
329                          ptd->conf.scale.zoom, ptd->conf.scale.w, ptd->conf.scale.h,
330                          ptd->conf.settings_req.is_grayscale);
331                 PTS_DEBUG("cmd: %s", ptd->previewgen_exe_cmd);
332                 break;
333         case FILE_TYPE_INCORRECT:
334                 PTS_DEBUG("Incorrect file type");
335                 PTS_IF_FREE_MEM(ptd->previewgen_exe_cmd);
336                 PTS_IF_FREE_MEM(ptd);
337                 PTS_TRACE_END;
338                 return -1;
339         }
340
341         /* TODO: clear task queue, disable generic tasks */
342         clear_preview_task_queue(model);
343
344         /* manage task queue */
345         if (NULL != model->previewgen_handle) {
346                 /* plan task for calculation in future */
347                 /* TODO: check, does we have current tasks in task model */
348                 model->task_list = eina_list_append(model->task_list, ptd);
349                 /* TODO: leave only 4 last page requests in queue */
350         } else {
351                 /* this task is a top task - just process */
352                 model->previewgen_handle = ecore_exe_pipe_run(
353                                 ptd->previewgen_exe_cmd,
354                                 ECORE_EXE_PIPE_READ, NULL);
355                 if (NULL == model->previewgen_handle) {
356                         PTS_DEBUG("ecore_exe_pipe_run error (%s)",
357                                         ptd->previewgen_exe_cmd);
358                         PTS_IF_FREE_MEM(ptd->previewgen_exe_cmd);
359                         destroy_preview_conf(&(ptd->conf));
360                         PTS_IF_FREE_MEM(ptd);
361                         PTS_TRACE_END;
362                         return 0;
363                 }
364                 model->event_handler = ecore_event_handler_add(
365                                 ECORE_EXE_EVENT_DATA,
366                                 preview_handler_end_cb, ptd);
367         }
368
369         PTS_TRACE_END;
370         return 0;
371 }
372
373
374 int process_preview_task_ptd(struct preview_task_model *model,
375                 struct preview_task_data *ptd)
376 {
377         struct preview_task_data *next_ptd;
378
379         PTS_TRACE_BEGIN;
380         PTS_RETV_IF(model == NULL || NULL == ptd,
381                         -1, "Argument error");
382
383         if (NULL != model->previewgen_handle) {
384                 if (NULL != model->task_list) {
385                         next_ptd = (struct preview_task_data *)
386                                            eina_list_data_get(model->task_list);
387                         if (next_ptd == NULL || PREVIEW_TASK_INITIAL
388                                         == next_ptd->task_type) {
389                                 /* incorret list content or initialization
390                                    is planned */
391                                 PTS_IF_FREE_MEM(ptd->previewgen_exe_cmd);
392                                 PTS_IF_FREE_MEM(ptd);
393                                 PTS_TRACE_END;
394                                 return 0;
395                         }
396                         /* plan task for calculation in future */
397                         model->task_list = eina_list_append(
398                                         model->task_list, ptd);
399                 } else { /* NULL == model->task_list */
400                         model->task_list = eina_list_append(
401                                 model->task_list, ptd);
402                 }
403                 /* TODO: leave only 4 last page requests in queue */
404         } else {
405                 /* this task is a top task - just process */
406                 model->previewgen_handle = ecore_exe_pipe_run(
407                                 ptd->previewgen_exe_cmd,
408                                 ECORE_EXE_PIPE_READ_LINE_BUFFERED
409                                 | ECORE_EXE_PIPE_READ, NULL);
410                 if (NULL == model->previewgen_handle) {
411                         PTS_DEBUG("ecore_exe_pipe_run error (%s)",
412                                         ptd->previewgen_exe_cmd);
413                         PTS_IF_FREE_MEM(ptd->previewgen_exe_cmd);
414                         PTS_IF_FREE_MEM(ptd);
415                         PTS_TRACE_END;
416                         return 0;
417                 }
418                 model->event_handler = ecore_event_handler_add(
419                                 ECORE_EXE_EVENT_DATA,
420                                 preview_handler_end_cb, ptd);
421         }
422
423         PTS_TRACE_END;
424         return 0;
425 }
426
427
428 int add_preview_task_empty_page(struct preview_task_model *model,
429                                          struct preview_model *pmodel)
430 {
431         PTS_TRACE_BEGIN;
432         PTS_RETV_IF(model == NULL || pmodel == NULL, -1, "Invalid argument");
433         PTS_RETV_IF(model->is_stop_processing, -1, "is_stop_processing is %d",
434                         model->is_stop_processing);
435
436         int res;
437         struct preview_task_data *ptd;
438         struct preview_task_data *next_ptd;
439
440         /* fill the preview_task_data structure */
441         ptd = malloc(sizeof(struct preview_task_data));
442         PTS_RETV_IF(ptd == NULL, -1, "malloc failed");
443
444         ptd->page = 0;
445         ptd->task_type = PREVIEW_TASK_EMPTY_PAGE;
446         sprintf(ptd->out_pic_fname, PREVIEW_TEMP_DIR "/empty_page.ppm");
447         ptd->is_task_ok = 0;
448         ptd->conf = pmodel->conf;
449         ptd->pmodel = pmodel;
450         ptd->task_model = model;
451
452         ptd->previewgen_exe_cmd = malloc(sizeof(char) * (CMD_STR_MAX_LEN + 1));
453         if (NULL == ptd->previewgen_exe_cmd) {
454                 PTS_IF_FREE_MEM(ptd);
455                 PTS_RETV_IF(ptd == NULL, -1, "malloc failed");
456         }
457
458         int to_be_previewed_as_landscape =
459                         (PAGE_ORIENTATION_LANDSCAPE == ptd->conf.orientation);
460         /* for number_up 2 page should be rotated to be viewed correctly */
461         if (2 == ptd->conf.n_up) {
462                 switch_size_pts_coords(&(ptd->conf.paper_size.s));
463                 //switch_size_px_coords(&(ptd->conf.settings_req.available_size_px));
464         }
465
466         /* fill cmd with arguments from ptd */
467         snprintf(ptd->previewgen_exe_cmd, CMD_STR_MAX_LEN,
468                         PREVIEWGEN_EXECUTABLE " empty_gen "
469                         "%s %lf %lf %d %d %d %d %d",
470                         ptd->out_pic_fname,
471                         ptd->conf.paper_size.s.x, ptd->conf.paper_size.s.y,
472                         ptd->conf.settings_req.available_size_px.x,
473                         ptd->conf.settings_req.available_size_px.y,
474                         ptd->conf.settings_req.shadow_offset.x,
475                         ptd->conf.settings_req.shadow_offset.y,
476                         to_be_previewed_as_landscape);
477         PTS_DEBUG("cmd: %s", ptd->previewgen_exe_cmd);
478
479         res = process_preview_task_ptd(model, ptd);
480
481         PTS_TRACE_END;
482         return res;
483 }
484
485
486 int add_preview_task(struct preview_task_model *model, int page,
487                                          struct preview_model *pmodel)
488 {
489         PTS_TRACE_BEGIN;
490         PTS_RETV_IF(model == NULL || pmodel == NULL , -1, "Invalid argument");
491         PTS_RETV_IF(model->is_stop_processing, -1, "is_stop_processing is %d", model->is_stop_processing);
492
493         int res;
494         struct preview_task_data *ptd;
495         struct preview_task_data *next_ptd;
496
497         /* fill the preview_task_data structure */
498         ptd = malloc(sizeof(struct preview_task_data));
499         PTS_RETV_IF(ptd == NULL, -1, "malloc failed");
500
501         ptd->page = page;
502         ptd->task_type = PREVIEW_TASK_GENERIC;
503         sprintf(ptd->out_pic_fname,
504                         "/tmp/mobileprint/mobileprint_%04d.ppm", page);
505         ptd->is_task_ok = 0;
506         ptd->conf = pmodel->conf;
507         ptd->pmodel = pmodel;
508         ptd->task_model = model;
509
510         ptd->previewgen_exe_cmd = malloc(sizeof(char) * (CMD_STR_MAX_LEN + 1));
511         if (NULL == ptd->previewgen_exe_cmd) {
512                 PTS_IF_FREE_MEM(ptd);
513                 PTS_RETV_IF(ptd == NULL, -1, "malloc failed");
514         }
515
516         int to_be_previewed_as_landscape = (PAGE_ORIENTATION_LANDSCAPE == ptd->conf.orientation);
517         /* for number_up 2 page should be rotated to be viewed correctly */
518         if (2 == ptd->conf.n_up) {
519                 switch_size_pts_coords(&(ptd->conf.paper_size.s));
520                 //switch_size_px_coords(&(ptd->conf.settings_req.available_size_px));
521         }
522
523         /* fill cmd with arguments from ptd */
524         snprintf(ptd->previewgen_exe_cmd, CMD_STR_MAX_LEN,
525                         PREVIEWGEN_EXECUTABLE " pagegen "
526                         "%s %d %s %lf %lf %d %d %d %d %d %d",
527                         ptd->conf.fname, page, ptd->out_pic_fname,
528                         ptd->conf.paper_size.s.x, ptd->conf.paper_size.s.y,
529                         ptd->conf.settings_req.available_size_px.x,
530                         ptd->conf.settings_req.available_size_px.y,
531                         ptd->conf.settings_req.shadow_offset.x,
532                         ptd->conf.settings_req.shadow_offset.y,
533                         to_be_previewed_as_landscape,
534                         ptd->conf.settings_req.is_grayscale);
535         PTS_DEBUG("cmd: %s", ptd->previewgen_exe_cmd);
536
537         res = process_preview_task_ptd(model, ptd);
538
539         PTS_TRACE_END;
540         return res;
541 }
542
543
544 int debug_print_preview_task_list(struct preview_task_model *model)
545 {
546         /*struct preview_task_data *ptd;
547         Eina_List *cur;
548         char *outstr;*/
549         PTS_DEBUG("task_list size: %d", eina_list_count(model->task_list));
550         return 0;
551 }
552