[Merge request] New map source infrastructure


I've finished the map source infrastructure we were discussing several
months ago. The result is here:


I'm sorry for announcing it so close to the API freeze date but I
wasn't able to finish the work earlier - partly because of lack of
free time, partly because it was much more work than I originally
expected (this is my first experience with gobject in C and you really
have to write a _lot_ of code just to create a basic class) and partly
because doing this was quite boring (there is nothing visibly
different from the current mainline - if everything is bug-free, it
should work the same way as before).

So the first question is - is it possible to merge this to get the
functionality into the next libchamplain release? I think the code is
in quite a good state now - I'm not aware of any regression compared
to mainline and delaying its merge for the next 6 months seems to be
too long time. If you decide for merging it now, then I guess the
first thing you should look at are the interfaces and let me know if
something needs to be changed/renamed/or whatever.

The good news is that if the current applications that use
libchamplain use MapFactory for creating map sources, their code can
remain unchanged - I didn't have to change a single line in any of the
demo applications (well, apart from one bugfix in launcher-gtk).

Now I'll briefly describe the new classes I've introduced:

Base class for all sources defining all the getter methods that the
view uses and the fill_tile() method - all of them are abstract
virtual. In addition, I added here the support for map source chaining
so you can get and set the next source in the chain here.

ChamplainTileSource : ChamplainMapSource (inherits from
ChamplainMapSource - using c++ notation)
Partially specialised ChamplainMapSource - base of all sources. It
contains properties common to all map sources and implements all
getters and setters for them (i.e. implements all the virtual getters
of ChamplainMapSource and defines non-virtual setters). It also
introduces a property for setting the cache that this map source uses
for storing its tiles.

ChamplainTileCache : ChamplainMapSource
Partially specialised ChamplainMapSource - base of all caches. It
forwards all the virtual getters to the next source in the chain
(continues this way until they reach ChamplainTileSource derived
class). In addition, it introduces the following abstract virtual

store_tile() - used by map sources to store tiles into cache
refresh_tile_time() - used by map sources when validating tile and the
tile is up-to-date and only the new time needs to be set
on_tile_filled() - when there are several caches in the chain, it
informs the other caches in the chain that the tile was filled by the
previous cache (so the other caches can update e.g. tile popularity
even if the tile is not filled by them)

ChamplainMapSourceChain : ChamplainMapSource
An envelope of the chain simplifying chain creation. It provides a
stack-like functions for adding and removing map sources from the
chain (it starts adding the map sources from the last in the chain to
the first). Internally it forwards all calls of ChamplainMapSource
interface to the map source at the top of the stack. See
champlain-map-source-factory.c where it is used.

ChamplainNetworkTileSource : ChamplainTileSource
Map source that loads tiles from the network and stores them into the
assigned cache. It providedes implementation of fill_tile() and all
other functions specific to this map source.

ChamplainErrorTileSource : ChamplainTileSource
Map source whose fill_tile() method creates an error tile (of course,
it doesn't store it into cache). It doesn't forward any call further
in the chain so everything stops here.

ChamplainFileCache : ChamplainTileCache
Implements all the 4 virtual methods (1 from ChamplainMapSource and 3
from ChamplainTileCache). When fill_tile() is called and the tile is
not found, it forwards the call to the next cache in the chain
(similarly for the other virtual methods).

The default chain that SourceFactory produces is:

ChamplainFileCache -> ChamplainNetworkTileSource -> ChamplainErrorTileSource

I've made a few changes when implementing these classes:

* I've removed CHAMPLAIN_STATE_VALIDATING completely. It would get
confusing because some sources in the chain could be setting
CHAMPLAIN_STATE_VALIDATING not returning it back to
CHAMPLAIN_STATE_LOADING and the tests wouldn't be reliable. Basically
what now determines whether fill_tile() should do tile validation is
whether the tile has some content - if it's non-NULL, validation is

* I've removed 'uri' and 'filename' properties of the tile - they
aren't needed at global scope and they "pollute" the tile with
map-source-specific data.

* In file cache I've removed the mechanism that stored tiles "on idle"
and store them directly instead - I think that the previous approach
didn't help at all - it just postponed the storage a bit, but still it
could be interleaved with clutter idle drawing methods and introducing
delays. However, what I did is that I replaced g_file_set_contents()
with deleting the file and creating it again. The reason is that
g_file_set_contents () "Writes all of contents to a file named
filename, with good error checking" - if you look at the sources it
calls fsync() which can slow things down quite a bit. The advantage of
the current implementation is that it has self-healing properties. If
the tile stored on the drive is corrupted and its loading fails, it
calls the map source that reloads it and stores it back in the cache.
So I think that "safe save" is not necessary now.

Nothing is perfect, so here are things that are still missing:

* documentation - I've removed all the documentation strings because
functions were changing classes and names so I realised that this will
be better to do from scratch (but with the help of the existing docs
of course) after everything settles down. Also if you decide that some
classes or functions need to change their name, it'll be easier now as

* no bindings yet

* I'd like to optimise the cache a bit more - the map movement isn't
smooth when loading tiles from it - the reason is that it's fighting
with clutter drawing on idle functions. However, we could use the
async methods of GFile or GSimpleAsyncResult - the action runs in a
separate thread and the functions only pass the result to some
callback function in the main thread. This means they shouldn't block
the clutter drawing functions. In addition, there could be one more
in-memory-only cache of most recently used tiles in front of
ChamplainFileCache - this could speed up things as well. Also
ErrorTileSource can be optimised a bit - the tile doesn't have to be
drawn by cairo every time it's requested but only once into a buffer
that would be used every time you call fill_tile() (you can see there
is a slow-down in full-screen).

*bug fixes - even though I don't see any bugs now, I'm pretty sure
there are some (I haven't tested the chaining functionality so much)

OK, that's about it - despite this long email I'm sure that I've
forgotten to mention something, so please ask if something is not

Have fun,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]