Code

Fixing preview/swatch sizes.
[inkscape.git] / src / uri-references.cpp
1 #define __SP_URI_REFERENCES_C__
3 /*
4  * Helper methods for resolving URI References
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *
9  * Copyright (C) 2001-2002 Lauris Kaplinski
10  * Copyright (C) 2001 Ximian, Inc.
11  *
12  * Released under GNU GPL, read the file 'COPYING' for more information
13  */
15 #include <cstring>
16 #include <string>
18 #include "document.h"
19 #include "sp-object.h"
20 #include "uri.h"
21 #include "uri-references.h"
22 #include "extract-uri.h"
24 #include <sigc++/functors/mem_fun.h>
26 namespace Inkscape {
28 URIReference::URIReference(SPObject *owner)
29         : _owner(owner), _owner_document(NULL), _obj(NULL), _uri(NULL)
30 {
31         g_assert(_owner != NULL);
32         /* FIXME !!! attach to owner's destroy signal to clean up in case */
33 }
35 URIReference::URIReference(SPDocument *owner_document)
36         : _owner(NULL), _owner_document(owner_document), _obj(NULL), _uri(NULL)
37 {
38         g_assert(_owner_document != NULL);
39 }
41 URIReference::~URIReference() {
42         detach();
43 }
45 void URIReference::attach(const URI &uri) throw(BadURIException)
46 {
47         SPDocument *document;
48   if (_owner) {
49     document = SP_OBJECT_DOCUMENT(_owner);
50         } else if (_owner_document) {
51     document = _owner_document;
52         } else {
53     g_assert_not_reached();
54         }
55         gchar const *fragment = uri.getFragment();
56         if ( !uri.isRelative() || uri.getQuery() || !fragment ) {
57                 throw UnsupportedURIException();
58         }
60         /* FIXME !!! real xpointer support should be delegated to document */
61         /* for now this handles the minimal xpointer form that SVG 1.0
62          * requires of us
63          */
64         gchar *id;
65         if (!strncmp(fragment, "xpointer(", 9)) {
66                 /* FIXME !!! this is wasteful */
67                 /* FIXME: It looks as though this is including "))" in the id.  I suggest moving
68                    the strlen calculation and validity testing to before strdup, and copying just
69                    the id without the "))".  -- pjrm */
70                 if (!strncmp(fragment, "xpointer(id(", 12)) {
71                         id = g_strdup(fragment+12);
72                         size_t const len = strlen(id);
73                         if ( len < 3 || strcmp(id+len-2, "))") ) {
74                                 g_free(id);
75                                 throw MalformedURIException();
76                         }
77                 } else {
78                         throw UnsupportedURIException();
79                 }
80         } else {
81                 id = g_strdup(fragment);
82         }
84         /* FIXME !!! validate id as an NCName somewhere */
86         if (_uri) {
87                 delete _uri;
88         }
89         _uri = new URI(uri);
91         _connection.disconnect();
92         _setObject(document->getObjectById(id));
93         _connection = document->connectIdChanged(id, sigc::mem_fun(*this, &URIReference::_setObject));
95         g_free(id);
96 }
98 void URIReference::detach() {
99         _connection.disconnect();
100         delete _uri;
101         _uri = NULL;
102         _setObject(NULL);
105 void URIReference::_setObject(SPObject *obj) {
106         if ( obj && !_acceptObject(obj) ) {
107                 obj = NULL;
108         }
110         if ( obj == _obj ) return;
112         SPObject *old_obj=_obj;
113         _obj = obj;
115         _release_connection.disconnect();
116         if (_obj) {
117                 sp_object_href(_obj, _owner);
118                 _release_connection = _obj->connectRelease(sigc::mem_fun(*this, &URIReference::_release));
119         }
120         _changed_signal.emit(old_obj, _obj);
121         if (old_obj) {
122                 /* release the old object _after_ the signal emission */
123                 sp_object_hunref(old_obj, _owner);
124         }
127 /* If an object is deleted, current semantics require that we release
128  * it on its "release" signal, rather than later, when its ID is actually
129  * unregistered from the document.
130  */
131 void URIReference::_release(SPObject *obj) {
132         g_assert( _obj == obj );
133         _setObject(NULL);
136 } /* namespace Inkscape */
138 SPObject* sp_css_uri_reference_resolve( SPDocument *document, const gchar *uri )
140     SPObject* ref = 0;
142     if ( document && uri && ( strncmp(uri, "url(", 4) == 0 )) {
143         gchar *trimmed = extract_uri( uri );
144         if ( trimmed ) {
145             ref = sp_uri_reference_resolve( document, trimmed );
146             g_free( trimmed );
147         }
148     }
150     return ref;
153 SPObject *
154 sp_uri_reference_resolve (SPDocument *document, const gchar *uri)
156     SPObject* ref = 0;
158     if ( uri && (*uri == '#') ) {
159         ref = document->getObjectById( uri + 1 );
160     }
162     return ref;