just kick off another build
[moon.git] / src / deepzoomimagetilesource.cpp
blob617ced1b62670390963874ceeb1d390e7ba276be
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * deepzoomimagetilesource.cpp
5 * Contact:
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007,2009 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
14 #include <config.h>
16 #include <stdio.h>
17 #include <math.h>
19 #include "debug.h"
20 #include "runtime.h"
22 #include "deepzoomimagetilesource.h"
23 #include "multiscalesubimage.h"
24 #include "uri.h"
25 #include "file-downloader.h"
27 class DisplayRect
29 public:
30 long min_level;
31 long max_level;
32 Rect rect;
34 DisplayRect (long minLevel, long maxLevel)
36 min_level = minLevel;
37 max_level = maxLevel;
41 class SubImage
43 public:
44 int id;
45 int n;
46 Uri *source;
47 long width;
48 long height;
49 double vp_x;
50 double vp_y;
51 double vp_w;
53 bool has_viewport;
54 bool has_size;
56 SubImage ()
58 source = NULL;
59 has_viewport = false;
60 has_size = false;
64 class DZParserinfo
66 public:
67 int depth;
68 int skip;
69 bool error;
70 DeepZoomImageTileSource *source;
72 bool isCollection;
74 //Image attributes
75 int overlap;
76 long image_width, image_height;
77 DisplayRect *current_rect;
78 GList *display_rects;
80 //Collection attributes
81 int max_level;
82 SubImage *current_subimage;
83 GList *sub_images;
85 //Common attributes
86 char *format;
87 int tile_size;
90 DZParserinfo ()
92 depth = 0;
93 skip = -1;
94 error = false;
95 format = NULL;
96 image_width = image_height = tile_size = overlap = 0;
97 current_rect = NULL;
98 display_rects = NULL;
99 sub_images = NULL;
100 current_subimage = NULL;
101 source = NULL;
105 void start_element (void *data, const char *el, const char **attr);
106 void end_element (void *data, const char *el);
108 bool
109 get_tile_layer (int level, int x, int y, Uri *uri, void *userdata)
111 return ((DeepZoomImageTileSource *)userdata)->GetTileLayer (level, x, y, uri);
114 void
115 DeepZoomImageTileSource::Init ()
117 SetObjectType (Type::DEEPZOOMIMAGETILESOURCE);
119 downloaded = false;
120 parsed = false;
121 format = NULL;
122 get_tile_func = get_tile_layer;
123 display_rects = NULL;
124 parsed_callback = NULL;
125 failed_callback = NULL;
126 sourcechanged_callback = NULL;
127 isCollection = false;
128 subimages = NULL;
129 nested = false;
130 get_resource_aborter = NULL;
131 parser = NULL;
134 DeepZoomImageTileSource::DeepZoomImageTileSource ()
136 Init ();
139 DeepZoomImageTileSource::DeepZoomImageTileSource (Uri *uri, bool nested)
141 Init ();
142 this->nested = nested;
143 strip_and_set_uri (uri);
146 //this is only meant to be used at construct time, if the uri is set from xaml, or using new DeepZoomImageTileSource (Uri)
147 // drt511 shows the new DeepZoomImageTileSource (Uri) behavior
148 // drt509 shows that sources set by setting the DP shouldn't be stripped
149 // http://www.silverlightshow.net/showcase/deepzoom/TestPage.html creates from xaml, and need ot be stripped
151 void
152 DeepZoomImageTileSource::strip_and_set_uri (Uri *uri)
154 if (!uri)
155 return;
156 char *s = uri->ToString ();
157 Uri stripped = Uri ();
158 if (g_str_has_prefix (s, "/"))
159 stripped.Parse (s + 1);
160 else
161 stripped.Parse (s);
162 SetValue (DeepZoomImageTileSource::UriSourceProperty, new Value (stripped));
165 DeepZoomImageTileSource::~DeepZoomImageTileSource ()
167 Abort ();
170 void
171 DeepZoomImageTileSource::Abort ()
173 if (get_resource_aborter)
174 get_resource_aborter->Cancel ();
175 if (parser)
176 XML_ParserFree (parser);
177 parser = NULL;
180 bool
181 DeepZoomImageTileSource::GetTileLayer (int level, int x, int y, Uri *uri)
183 //check if there tile is listed in DisplayRects
184 if (display_rects) {
185 DisplayRect *cur;
186 int i =0;
187 bool found = false;
188 int layers;
190 frexp ((double) MAX (GetImageWidth (), GetImageHeight ()), &layers);
192 while ((cur = (DisplayRect*)g_list_nth_data (display_rects, i))) {
193 i++;
195 if (!(cur->min_level <= level && level <= cur->max_level))
196 continue;
198 int vtilesize = GetTileWidth () * (layers + 1 - level);
199 Rect virtualtile = Rect (x * vtilesize, y * vtilesize, vtilesize, vtilesize);
200 if (cur->rect.IntersectsWith (virtualtile)) {
201 found = true;
202 break;
206 if (!found)
207 return false;
210 const Uri *baseUri = GetValue (DeepZoomImageTileSource::UriSourceProperty)->AsUri ();
211 const char *filename, *ext;
212 char *image;
214 if (!baseUri)
215 return false;
217 if ((filename = strrchr (baseUri->path, '/')))
218 filename ++;
219 else
220 filename = baseUri->path;
222 if (!(ext = strrchr (filename, '.')))
223 return false;
225 image = g_strdup_printf ("%.*s_files/%d/%d_%d.%s", ext - filename, filename, level, x, y, format);
227 Uri::Copy (baseUri, uri);
228 uri->Combine (image);
229 g_free (image);
231 return true;
234 static void
235 resource_notify (NotifyType type, gint64 args, gpointer user_data)
237 DeepZoomImageTileSource *dzits = (DeepZoomImageTileSource *)user_data;
238 if (type == NotifyFailed)
239 dzits->DownloaderFailed ();
240 else if (type == NotifyCompleted)
241 dzits->DownloaderComplete ();
244 static void
245 dz_write (void *buffer, gint32 offset, gint32 n, gpointer data)
247 DeepZoomImageTileSource *dzits = (DeepZoomImageTileSource *) data;
248 dzits->XmlWrite ((char *) buffer, offset, n);
251 void
252 DeepZoomImageTileSource::XmlWrite (char* buffer, gint32 offset, gint32 n)
254 if (offset == 0) {
255 //Init xml parser
256 LOG_MSI ("Start parsing DeepZoom\n");
257 parser = XML_ParserCreate (NULL);
258 XML_SetElementHandler (parser, start_element, end_element);
259 DZParserinfo *info = new DZParserinfo ();
260 info->source = this;
261 XML_SetUserData (parser, info);
264 if (!XML_Parse (parser, buffer, n, 0)) {
265 printf ("Parser error at line %d:\n%s\n", (int)XML_GetCurrentLineNumber (parser), XML_ErrorString(XML_GetErrorCode(parser)));
266 Abort ();
267 DownloaderFailed ();
271 void
272 DeepZoomImageTileSource::Download ()
274 LOG_MSI ("DZITS::Download ()\n");
275 if (downloaded)
276 return;
278 Application *current = Application::GetCurrent ();
279 Uri *uri = GetUriSource ();
281 if (current && uri) {
282 downloaded = true;
283 get_resource_aborter = new Cancellable ();
284 current->GetResource (GetResourceBase(), uri, resource_notify, dz_write, MediaPolicy, get_resource_aborter, this);
288 void
289 DeepZoomImageTileSource::DownloaderComplete ()
291 //set isFinal for the parser to complete
292 if (!XML_Parse (parser, NULL, 0, 1)) {
293 printf ("Parser error at line %d:\n%s\n", (int)XML_GetCurrentLineNumber (parser), XML_ErrorString(XML_GetErrorCode(parser)));
294 Abort ();
295 DownloaderFailed ();
296 return;
299 DZParserinfo *info = (DZParserinfo *)XML_GetUserData (parser);
301 if (!info->isCollection) {
302 SetImageWidth (info->image_width);
303 SetImageHeight (info->image_height);
304 SetTileOverlap (info->overlap);
305 display_rects = info->display_rects;
306 } else {
307 subimages = info->sub_images;
308 isCollection = info->isCollection;
309 maxLevel = info->max_level;
312 SetTileWidth (info->tile_size);
313 SetTileHeight (info->tile_size);
314 format = g_strdup (info->format);
316 parsed = true;
318 LOG_MSI ("Done parsing...\n");
320 XML_ParserFree (parser);
321 parser = NULL;
323 if (parsed_callback)
324 parsed_callback (cb_userdata);
327 void
328 DeepZoomImageTileSource::DownloaderFailed ()
330 LOG_MSI ("DZITS::dl failed\n");
331 if (failed_callback)
332 failed_callback (cb_userdata);
335 void
336 DeepZoomImageTileSource::UriSourceChanged ()
338 parsed = false;
339 downloaded = false;
340 if (!nested) {
341 Download ();
344 if (sourcechanged_callback)
345 sourcechanged_callback (cb_userdata);
348 void
349 DeepZoomImageTileSource::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error)
351 if (args->GetId () == DeepZoomImageTileSource::UriSourceProperty) {
352 Abort ();
353 UriSourceChanged ();
356 if (args->GetProperty ()->GetOwnerType () != Type::DEEPZOOMIMAGETILESOURCE) {
357 DependencyObject::OnPropertyChanged (args, error);
358 return;
361 NotifyListenersOfPropertyChange (args, error);
364 //DeepZoomParsing
365 void
366 start_element (void *data, const char *el, const char **attr)
368 DZParserinfo *info = (DZParserinfo*)data;
370 if (info->skip >= 0) {
371 (info->depth)++;
372 return;
374 switch (info->depth) {
375 case 0:
376 //Image or Collection
377 if (!g_ascii_strcasecmp ("Image", el)) {
378 info->isCollection = false;
379 int i;
380 for (i = 0; attr[i]; i+=2)
381 if (!g_ascii_strcasecmp ("Format", attr[i]))
382 info->format = g_strdup (attr[i+1]);
383 else if (!g_ascii_strcasecmp ("TileSize", attr[i]))
384 info->tile_size = atoi (attr[i+1]);
385 else if (!g_ascii_strcasecmp ("Overlap", attr[i]))
386 info->overlap = atoi (attr[i+1]);
387 else
388 LOG_MSI ("\tunparsed attr %s: %s\n", attr[i], attr[i+1]);
389 } else if (!g_ascii_strcasecmp ("Collection", el)) {
390 info->isCollection = true;
391 int i;
392 for (i = 0; attr[i]; i+=2)
393 if (!g_ascii_strcasecmp ("Format", attr[i]))
394 info->format = g_strdup (attr[i+1]);
395 else if (!g_ascii_strcasecmp ("TileSize", attr[i]))
396 info->tile_size = atoi (attr[i+1]);
397 else if (!g_ascii_strcasecmp ("MaxLevel", attr[i]))
398 info->max_level = atoi (attr[i+1]);
399 else
400 LOG_MSI ("\tunparsed attr %s: %s\n", attr[i], attr[i+1]);
401 } else {
402 printf ("Unexpected element %s\n", el);
403 info->error = true;
405 break;
406 case 1:
407 if (!info->isCollection) {
408 //Size or DisplayRects
409 if (!g_ascii_strcasecmp ("Size", el)) {
410 int i;
411 for (i = 0; attr[i]; i+=2)
412 if (!g_ascii_strcasecmp ("Width", attr[i]))
413 info->image_width = atol (attr[i+1]);
414 else if (!g_ascii_strcasecmp ("Height", attr[i]))
415 info->image_height = atol (attr[i+1]);
416 else
417 LOG_MSI ("\tunparsed attr %s: %s\n", attr[i], attr[i+1]);
418 } else if (!g_ascii_strcasecmp ("DisplayRects", el)) {
419 //no attributes, only contains DisplayRect element
420 } else {
421 printf ("Unexpected element %s\n", el);
422 info->error = true;
424 } else {
425 if (!g_ascii_strcasecmp ("Items", el)) {
426 //no attributes, only contains <I> elements
427 } else {
428 printf ("Unexpected element %d %s\n", info->depth, el);
429 info->error = true;
432 break;
433 case 2:
434 if (!info->isCollection) {
435 //DisplayRect elts
436 if (!g_ascii_strcasecmp ("DisplayRect", el)) {
437 long min_level, max_level;
438 int i;
439 for (i = 0; attr[i]; i+=2)
440 if (!g_ascii_strcasecmp ("MinLevel", attr[i]))
441 min_level = atol (attr[i+1]);
442 else if (!g_ascii_strcasecmp ("MaxLevel", attr[i]))
443 max_level = atol (attr[i+1]);
444 else
445 LOG_MSI ("\tunparsed arg %s: %s\n", attr[i], attr[i+1]);
446 info->current_rect = new DisplayRect (min_level, max_level);
447 } else {
448 printf ("Unexpected element %s\n", el);
449 info->error = true;
451 } else {
452 if (!g_ascii_strcasecmp ("I", el)) {
453 info->current_subimage = new SubImage ();
454 int i;
455 for (i = 0; attr[i]; i+=2)
456 if (!g_ascii_strcasecmp ("N", attr[i]))
457 info->current_subimage->n = atoi (attr[i+1]);
458 else if (!g_ascii_strcasecmp ("Id", attr[i]))
459 info->current_subimage->id = atoi (attr[i+1]);
460 else if (!g_ascii_strcasecmp ("Source", attr[i])) {
461 info->current_subimage->source = new Uri ();
462 info->current_subimage->source->Parse (attr[i+1]);
463 } else
464 LOG_MSI ("\tunparsed arg %s: %s\n", attr[i], attr[i+1]);
466 } else {
467 printf ("Unexpected element %d %s\n", info->depth, el);
468 info->error = true;
471 break;
472 case 3:
473 if (!info->isCollection) {
474 //Rect elt
475 if (!g_ascii_strcasecmp ("Rect", el)) {
476 if (!info->current_rect) {
477 info->error = true;
478 break;
480 int i;
481 for (i = 0; attr[i]; i+=2)
482 if (!g_ascii_strcasecmp ("X", attr[i]))
483 info->current_rect->rect.x = (double)atol (attr[i+1]);
484 else if (!g_ascii_strcasecmp ("Y", attr[i]))
485 info->current_rect->rect.y = (double)atol (attr[i+1]);
486 else if (!g_ascii_strcasecmp ("Width", attr[i]))
487 info->current_rect->rect.width = (double)atol (attr[i+1]);
488 else if (!g_ascii_strcasecmp ("Height", attr[i]))
489 info->current_rect->rect.height = (double)atol (attr[i+1]);
490 else
491 LOG_MSI ("\tunparsed attr %s: %s\n", attr[i], attr[i+1]);
492 info->display_rects = g_list_append (info->display_rects, info->current_rect);
493 info->current_rect = NULL;
494 } else {
495 printf ("Unexpected element %s\n", el);
496 info->error = true;
498 } else {
499 if (!g_ascii_strcasecmp ("Size", el)) {
500 if (!info->current_subimage) {
501 info->error = true;
502 break;
505 info->current_subimage->has_size = true;
507 int i;
508 for (i = 0; attr [i]; i+=2)
509 if (!g_ascii_strcasecmp ("Width", attr[i]))
510 info->current_subimage->width = atol (attr[i+1]);
511 else if (!g_ascii_strcasecmp ("Height", attr[i]))
512 info->current_subimage->height = atol (attr[i+1]);
513 else
514 LOG_MSI ("\tunparsed attr %s.%s: %s\n", el, attr[i], attr[i+1]);
515 } else if (!g_ascii_strcasecmp ("Viewport", el)) {
516 if (!info->current_subimage) {
517 info->error = true;
518 break;
521 info->current_subimage->has_viewport = true;
523 int i;
524 for (i = 0; attr [i]; i+=2)
525 if (!g_ascii_strcasecmp ("X", attr[i]))
526 info->current_subimage->vp_x = g_ascii_strtod (attr[i+1], NULL);
527 else if (!g_ascii_strcasecmp ("Y", attr[i]))
528 info->current_subimage->vp_y = g_ascii_strtod (attr[i+1], NULL);
529 else if (!g_ascii_strcasecmp ("Width", attr[i]))
530 info->current_subimage->vp_w = g_ascii_strtod (attr[i+1], NULL);
531 else
532 LOG_MSI ("\tunparsed attr %s: %s\n", attr[i], attr[i+1]);
533 } else {
534 printf ("Unexpected element %s\n", el);
535 info->error = true;
538 break;
542 (info->depth)++;
545 void
546 DeepZoomImageTileSource::EndElement (void *data, const char *el)
548 DZParserinfo *info = (DZParserinfo*)data;
549 (info->depth)--;
551 if (info->skip < 0) {
552 switch (info->depth) {
553 case 2:
554 if (info->isCollection)
555 if (!g_ascii_strcasecmp ("I", el)) {
556 DeepZoomImageTileSource *subsource = new DeepZoomImageTileSource (info->current_subimage->source, TRUE);
557 MultiScaleSubImage *subi = new MultiScaleSubImage (info->source->GetUriSource (),
558 subsource,
559 info->current_subimage->id,
560 info->current_subimage->n);
561 subsource->SetImageWidth (info->current_subimage->width);
562 subsource->SetImageHeight (info->current_subimage->height);
563 subsource->format = info->format;
564 if (info->current_subimage->has_viewport) {
565 subi->SetViewportOrigin (new Point (info->current_subimage->vp_x, info->current_subimage->vp_y));
566 subi->SetViewportWidth (info->current_subimage->vp_w);
569 if (info->current_subimage->has_size) {
570 subi->SetValue (MultiScaleSubImage::AspectRatioProperty, Value ((double)info->current_subimage->width/(double)info->current_subimage->height));
572 info->sub_images = g_list_append (info->sub_images, subi);
573 info->current_subimage = NULL;
575 break;
579 if (info->skip == info->depth)
580 info->skip = -1;
583 void
584 end_element (void *data, const char *el)
586 DZParserinfo *info = (DZParserinfo*)data;
587 DeepZoomImageTileSource *dzits = (DeepZoomImageTileSource*)info->source;
588 if (!dzits)
589 g_assert ("That's wrong...\n");
590 dzits->EndElement (info, el);