From ac73bb08ea1d84e9a83b6b6960d3f265411d3521 Mon Sep 17 00:00:00 2001 From: billh Date: Fri, 16 Jun 2006 15:05:32 +0000 Subject: [PATCH] Implement RFE #326532: remove BonoboStream usage from at-spi's StreamableContent interface, and add getURI method. git-svn-id: http://svn.gnome.org/svn/at-spi/trunk@823 e2bd861d-eb25-0410-b326-f6ed22b6b98c --- ChangeLog | 48 +++++++++ cspi/spi_streamablecontent.c | 91 +++++++++++++--- idl/Accessibility_StreamableContent.idl | 127 +++++++++++++++++----- libspi/streamablecontent.c | 181 ++++++++++++++++++++++++++++++++ 4 files changed, 402 insertions(+), 45 deletions(-) diff --git a/ChangeLog b/ChangeLog index 59a25c3..818eaf9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,51 @@ +2006-06-16 Bill Haneman + + RFE #326532: + + * idl/Accessibility_StreambleContent.idl: + Deprecate the Bonobo_Stream-based methods in favor of + a self-contained "ContentStream" interface. This should + allow us to remove BonoboStream dependencies entirely, since + there were no non-NIL implementations of the old methods anyway. + (ContentStream): New interface. + (ContentStream::SeekType): Enum. + (ContentStream::seek): New. + (ContentStream::read): New. + (ContentStream::close): New. + (getContent): Deprecate. + (getURI): New method, returns a URI pointing to the content, if available. + + * libspi/streamablecontent.c: + (SpiContentStream): Internal object type definition used to + implement Accessibility::StreamableContent::ContentStream via + AtkStreamableContent's GIOChannel back-end. + (spi_content_stream_new, spi_content_stream_dispose): See above; + static methods. + (impl_content_stream_seek, impl_content_stream_read): + (impl_content_stream_close): New, implementations of + ContentStream's IDL. + (impl_accessibility_streamable_get_stream): Implement the + public method Accessibility::StreamableContent::getStream. + (impl_accessibility_streamable_get_uri): Implement the + public method Accessibility::StreamableContent::getURI. + + * cspi/spi_streamablecontent.c: + (accessible_bonobo_stream_client_seek): Replaced by + (accessible_content_stream_client_seek). + (accessible_bonobo_stream_client_read): Replaced by + (accessible_content_stream_client_read). + (AccessibleStreamableContent_open): + (AccessibleStreamableContent_seek): + (AccessibleStreamableContent_read): + (AccessibleStreamableContent_close): Use the new 'getStream' + API instead of the deprecated 'getContent' API, inside the cspi wrappers. + +2006-06-15 Bill Haneman + + * idl/Accessibility.idl: #include Bonobo_Unknown.idl, + remove from other .idl files (except LoginHelper). + See bug #313122. + 2006-06-14 Bill Haneman * */Makefile.am: Add WARN_CFLAGS to INCLUDES. diff --git a/cspi/spi_streamablecontent.c b/cspi/spi_streamablecontent.c index 2e0c080..8b6b266 100644 --- a/cspi/spi_streamablecontent.c +++ b/cspi/spi_streamablecontent.c @@ -25,11 +25,10 @@ #include #include - -/* TODO: factor/wrap Bonobo_Stream dependency to cspi/bonobo */ +#define CORBA_BLOCK_SIZE 65536 /* see libbonobo, dunno where this is officially dictated */ struct StreamCacheItem { - Bonobo_Stream stream; + Accessibility_ContentStream stream; gchar *mimetype; }; @@ -62,9 +61,9 @@ get_streams (void) } static CORBA_long -accessible_bonobo_stream_client_seek (const Bonobo_Stream stream, +accessible_content_stream_client_seek (const Accessibility_ContentStream stream, CORBA_long offset, - Bonobo_Stream_SeekType seek_type, + Accessibility_ContentStream_SeekType seek_type, CORBA_Environment *opt_ev) { CORBA_Environment *ev, temp_ev; @@ -76,7 +75,7 @@ accessible_bonobo_stream_client_seek (const Bonobo_Stream stream, } else ev = opt_ev; - ret_offset = Bonobo_Stream_seek (stream, offset, seek_type, ev); + ret_offset = Accessibility_ContentStream_seek (stream, offset, seek_type, ev); if (BONOBO_EX (ev)) ret_offset = -1; @@ -86,6 +85,65 @@ accessible_bonobo_stream_client_seek (const Bonobo_Stream stream, return ret_offset; } +static guint8* +accessible_content_stream_client_read (const Accessibility_ContentStream stream, + const size_t size, + CORBA_long *length_read, + CORBA_Environment *ev) +{ + size_t pos; + guint8 *mem; + size_t length; + + g_return_val_if_fail (ev != NULL, NULL); + + if (length_read) + *length_read = size; + + length = size; + + if (length == 0) + return NULL; + + mem = g_try_malloc (length); + if (!mem) { + CORBA_exception_set_system (ev, ex_CORBA_NO_MEMORY, + CORBA_COMPLETED_NO); + return NULL; + } + + *length_read = 0; + + for (pos = 0; pos < length;) { + Bonobo_Stream_iobuf *buf; + CORBA_long len; + + len = (pos + CORBA_BLOCK_SIZE < length) ? + CORBA_BLOCK_SIZE : length - pos; + + Accessibility_ContentStream_read (stream, len, &buf, ev); + + if (BONOBO_EX (ev) || !buf) + goto io_error; + + if (buf->_length > 0) { + memcpy (mem + pos, buf->_buffer, buf->_length); + pos += buf->_length; + } else { + g_warning ("Buffer length %d", buf->_length); + goto io_error; + } + *length_read += buf->_length; + + CORBA_free (buf); + } + + return mem; + + io_error: + return NULL; +} + /* internal use only, declared in cspi-private.h */ void cspi_streams_close_all (void) @@ -205,7 +263,7 @@ SPIBoolean AccessibleStreamableContent_open (AccessibleStreamableContent *obj, const char *content_type) { - Bonobo_Stream stream; + Accessibility_ContentStream stream; struct StreamCacheItem *cache; stream = Accessibility_StreamableContent_getContent (CSPI_OBJREF (obj), content_type, @@ -266,10 +324,10 @@ AccessibleStreamableContent_seek (AccessibleStreamableContent *obj, long int offset, AccessibleStreamableContentSeekType seek_type) { - Bonobo_Stream stream; + Accessibility_ContentStream stream; long int ret_offset = 0; struct StreamCacheItem *cached; - Bonobo_Stream_SeekType bonobo_seek_type; + Accessibility_ContentStream_SeekType content_seek_type; cached = g_hash_table_lookup (get_streams (), CSPI_OBJREF (obj)); if (cached) @@ -279,19 +337,18 @@ AccessibleStreamableContent_seek (AccessibleStreamableContent *obj, { switch (seek_type) { case SPI_STREAM_SEEK_SET: - bonobo_seek_type = Bonobo_Stream_SeekSet; + content_seek_type = Accessibility_ContentStream_SEEK_SET; break; case SPI_STREAM_SEEK_END: - bonobo_seek_type = Bonobo_Stream_SeekEnd; + content_seek_type = Accessibility_ContentStream_SEEK_END; break; case SPI_STREAM_SEEK_CUR: default: - bonobo_seek_type = Bonobo_Stream_SeekCur; + content_seek_type = Accessibility_ContentStream_SEEK_CURRENT; break; } - /* bonobo-client doesn't wrap seek yet, so we have to. */ - ret_offset = accessible_bonobo_stream_client_seek (stream, offset, - bonobo_seek_type, cspi_ev ()); + ret_offset = accessible_content_stream_client_seek (stream, offset, + content_seek_type, cspi_ev ()); cspi_return_val_if_ev ("seek", FALSE); } } @@ -323,7 +380,7 @@ AccessibleStreamableContent_read (AccessibleStreamableContent *obj, long int nbytes, unsigned int read_type) { - Bonobo_Stream stream; + Accessibility_ContentStream stream; struct StreamCacheItem *cached; cached = g_hash_table_lookup (get_streams (), CSPI_OBJREF (obj)); if (cached) @@ -333,7 +390,7 @@ AccessibleStreamableContent_read (AccessibleStreamableContent *obj, if (stream != CORBA_OBJECT_NIL) { guint8 *mem; - mem = bonobo_stream_client_read (stream, (size_t) nbytes, &len_read, cspi_ev ()); + mem = accessible_content_stream_client_read (stream, (size_t) nbytes, &len_read, cspi_ev ()); cspi_return_val_if_ev ("read", FALSE); if (mem) { diff --git a/idl/Accessibility_StreamableContent.idl b/idl/Accessibility_StreamableContent.idl index c552a63..0f1ac1e 100644 --- a/idl/Accessibility_StreamableContent.idl +++ b/idl/Accessibility_StreamableContent.idl @@ -27,35 +27,16 @@ module Accessibility { typedef sequence StringSeq; /** - * An interface whereby an object allows its backing content - * to be streamed to clients. Negotiation of content type - * is allowed. Clients may examine the backing data and - * transform, convert, or parse the content in order to - * present it in an alternate form to end-users. + * An interface by which the requested data from a StreamableContent object + * may be read by the client. + * @note this interface supercedes the use of BonoboStream by previous + * versions of StreamableContent. * - * @note The StreamableContent interface is particularly useful for saving, - * printing, or post-processing entire documents, or for persisting - * alternate views of a document. - * If document content itself is being serialized, stored, or converted, - * then use of the StreamableContent interface can help address performance - * issues. Unlike most AT-SPI/Accessibility interfaces, this interface - * is not strongly tied to the current user-agent view of the - * a particular document, but may in some cases give access to the - * underlying model data. + * @since AT-SPI 1.7.0 */ - interface StreamableContent { + interface ContentStream { - /** - * Specifies the meaning of a seek 'offset'. Not all SeekTypes are - * supported by all StreamableContent data sources, for instance - * some streams may not support seeking from the beginning or other - * types of 'backwards' seeks. - */ - enum SeekType { - SEEK_SET, /**< Seek from the start of the stream or data source.*/ - SEEK_CURRENT, /**< Seek relative to the current position. */ - SEEK_END /**< Seek from the end of the file, stream, or data source. */ - }; + typedef sequence iobuf; /** * Indicates that a transmission error has occurred while @@ -80,12 +61,76 @@ module Accessibility { string reason; }; + /** + * Specifies the meaning of a seek 'offset'. Not all SeekTypes are + * supported by all StreamableContent data sources, for instance + * some streams may not support seeking from the beginning or other + * types of 'backwards' seeks. + */ + enum SeekType { + SEEK_SET, /**< Seek from the start of the stream or data source.*/ + SEEK_CURRENT, /**< Seek relative to the current position. */ + SEEK_END /**< Seek from the end of the file, stream, or data source. */ + }; + + /** + * Seek to a specified position in the Stream. + * @param offset an offset specifying the requested position in the stream, + * relative to the SeekType specified in \c whence. + * @param whence a SeekType specifying the reference point from which the + * seek offset is calculated. Some forms of seek are not supported by certain + * implementations of Stream, in which case a NotSupported exception will be raised. + * @returns the actual resulting offset, if no exception was raised. + **/ + long seek (in long offset, in SeekType whence) + raises (NoPermission, IOError, NotSupported); + /** + * Request/read a specified amount of data from a Stream. + * @returns the number of bytes actually read into the client buffer. + **/ + long read (in long count, out iobuf buffer) + raises (NoPermission, IOError); + /** + * close the stream and release associated resources. + * A client should not perform further operations on a + * StreamableContent::Stream object after closing it. + **/ + void close (); + + /** /cond */ + void unimplemented (); + void unimplemented2 (); + /** /endcond */ + }; + + + /** + * An interface whereby an object allows its backing content + * to be streamed to clients. Negotiation of content type + * is allowed. Clients may examine the backing data and + * transform, convert, or parse the content in order to + * present it in an alternate form to end-users. + * + * @note The StreamableContent interface is particularly useful for saving, + * printing, or post-processing entire documents, or for persisting + * alternate views of a document. + * If document content itself is being serialized, stored, or converted, + * then use of the StreamableContent interface can help address performance + * issues. Unlike most AT-SPI/Accessibility interfaces, this interface + * is not strongly tied to the current user-agent view of the + * a particular document, but may in some cases give access to the + * underlying model data. + */ + interface StreamableContent { + /** * getContentTypes: * @returns the list of available mimetypes for this object's content. */ StringSeq getContentTypes (); /** + * \n DEPRECATED, use getStream instead. + * getContent: * Retrieve this object's content, in a format appropriate to a * requested mimetype. * @@ -109,6 +154,33 @@ module Accessibility { */ Bonobo::Stream getContent (in string contentType); + /** + * Retrieve this object's content, in a format appropriate to a + * requested mimetype, as a ::ContentStream instance. + * + * @note This method supercedes the older getContent method, which + * relied on the Bonobo::Stream API. + * \c seek may not be supported for all mimetypes or + * all implementors. + * + * @param contentType a string specifying the desired mimetype for the content stream. + * @returns a Stream whose mimetype matches \a contentType, + * if available, or \c NIL. + * @since AT-SPI 1.8.0 + */ + ContentStream getStream (in string contentType); + + /** + * Get a URI pointing to the content of the specified type, if such a URI + * can be obtained. Not all streamable content providers have URI representations. + * + * @param contentType a string specifying the desired mimetype for the content stream. + * If NULL, then a URI for the default content type will be returned, if available. + * + * @returns a string which constitutes a URI for a stream of the specified + * content type, or NULL if no such URI can be obtained. + */ + string getURI (in string contentType); /** * \cond * unImplemented: @@ -117,8 +189,7 @@ module Accessibility { */ void unImplemented (); void unImplemented2 (); - void unImplemented3 (); - void unImplemented4 (); /** \endcond */ }; + }; diff --git a/libspi/streamablecontent.c b/libspi/streamablecontent.c index df66141..51c4579 100644 --- a/libspi/streamablecontent.c +++ b/libspi/streamablecontent.c @@ -35,6 +35,146 @@ /* A pointer to our parent object class */ static GObjectClass *spi_streamable_parent_class; +#define SPI_CONTENT_STREAM_TYPE (spi_content_stream_get_type ()) +#define SPI_CONTENT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SPI_CONTENT_STREAM_TYPE, SpiContentStream)) +#define SPI_CONTENT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), SPI_CONTENT_STREAM_TYPE, SpiContentStreamClass)) +#define SPI_IS_CONTENT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SPI_CONTENT_STREAM_TYPE)) +#define SPI_IS_CONTENT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SPI_CONTENT_STREAM_TYPE)) + +typedef struct _SpiContentStream SpiContentStream; +typedef struct _SpiContentStreamClass SpiContentStreamClass; + +struct _SpiContentStream { + BonoboObject parent; + GIOChannel *gio; +}; + +struct _SpiContentStreamClass { + BonoboObjectClass parent_class; + POA_Accessibility_ContentStream__epv epv; +}; + +GType spi_content_stream_get_type (void); + +static SpiContentStream* +spi_content_stream_new (GIOChannel *gio) +{ + SpiContentStream *new_stream = g_object_new (SPI_CONTENT_STREAM_TYPE, NULL); + new_stream->gio = gio; + return new_stream; +} + +static void +spi_content_stream_dispose (GObject *o) +{ + if (SPI_IS_CONTENT_STREAM (o)) + { + SpiContentStream *stream = SPI_CONTENT_STREAM (o); + if (stream->gio) g_io_channel_unref (stream->gio); + } +} + +static CORBA_long +impl_content_stream_seek (PortableServer_Servant servant, + const CORBA_long offset, + const Accessibility_ContentStream_SeekType whence, + CORBA_Environment *ev) +{ + SpiContentStream *stream = SPI_CONTENT_STREAM (bonobo_object_from_servant(servant)); + if (stream && stream->gio) + { + GError *err; + GSeekType seektype = G_SEEK_SET; + switch (whence) { + case Accessibility_ContentStream_SEEK_CURRENT: + seektype = G_SEEK_CUR; + break; + case Accessibility_ContentStream_SEEK_END: + seektype = G_SEEK_END; + break; + } + if (g_io_channel_seek_position (stream->gio, (gint64) offset, + seektype, &err) == G_IO_STATUS_NORMAL) + return offset; + else + return -1; + } + else + return -1; +} + +static CORBA_long +impl_content_stream_read (PortableServer_Servant servant, + const CORBA_long count, + Accessibility_ContentStream_iobuf** buffer, + CORBA_Environment *ev) +{ + SpiContentStream *stream = SPI_CONTENT_STREAM (bonobo_object_from_servant(servant)); + CORBA_long realcount = 0; + if (stream && stream->gio) + { + gchar *gbuf = NULL; + GIOStatus status; + GError *err; + /* read the giochannel and determine the actual bytes read...*/ + if (count != -1) + status = g_io_channel_read_chars (stream->gio, &gbuf, count, &realcount, &err); + else + status = g_io_channel_read_to_end (stream->gio, &gbuf, &realcount, &err); + + if (status == G_IO_STATUS_NORMAL || status == G_IO_STATUS_EOF) + { + *buffer = Bonobo_Stream_iobuf__alloc (); + CORBA_sequence_set_release (*buffer, TRUE); + + (*buffer)->_buffer = CORBA_sequence_CORBA_octet_allocbuf (realcount); + (*buffer)->_length = realcount; + + memcpy ((*buffer)->_buffer, gbuf, realcount); + } + + g_free (gbuf); + } + + return realcount; +} + +static void +impl_content_stream_close (PortableServer_Servant servant, + CORBA_Environment *ev) +{ + GIOStatus status; + GError *err; + SpiContentStream *stream = SPI_CONTENT_STREAM (bonobo_object_from_servant(servant)); + if (stream && stream->gio) status = g_io_channel_shutdown (stream->gio, TRUE, &err); + if (err) g_free (err); +} + +static void +spi_content_stream_class_init (SpiContentStreamClass *klass) +{ + POA_Accessibility_ContentStream__epv *epv = &klass->epv; + GObjectClass * object_class = (GObjectClass *) klass; + + epv->seek = impl_content_stream_seek; + epv->read = impl_content_stream_read; + epv->close = impl_content_stream_close; + + object_class->dispose = spi_content_stream_dispose; +} + + +static void +spi_content_stream_init (SpiContentStream *stream) +{ +} + + +BONOBO_TYPE_FUNC_FULL (SpiContentStream, + Accessibility_ContentStream, + BONOBO_TYPE_OBJECT, + spi_content_stream) + static AtkStreamableContent * get_streamable_from_servant (PortableServer_Servant servant) { @@ -90,6 +230,45 @@ impl_accessibility_streamable_get_content (PortableServer_Servant servant, return stream; } +/* + * CORBA Accessibility::StreamableContent::getStream method implementation + */ +static Accessibility_ContentStream +impl_accessibility_streamable_get_stream (PortableServer_Servant servant, + const CORBA_char * content_type, + CORBA_Environment *ev) +{ + SpiContentStream *stream; + AtkStreamableContent *streamable = get_streamable_from_servant (servant); + GIOChannel *gio; + + g_return_val_if_fail (streamable != NULL, NULL); + + gio = atk_streamable_content_get_stream (streamable, content_type); + + stream = spi_content_stream_new (gio); + + return bonobo_object_dup_ref (BONOBO_OBJREF (stream), ev); +} + +/* + * CORBA Accessibility::StreamableContent::getURI method implementation + */ +static CORBA_string +impl_accessibility_streamable_get_uri (PortableServer_Servant servant, + const CORBA_char * content_type, + CORBA_Environment *ev) +{ + gchar *uri; + AtkStreamableContent *streamable = get_streamable_from_servant (servant); + + g_return_val_if_fail (streamable != NULL, NULL); + + uri = atk_streamable_content_get_uri (streamable, content_type); + + return (uri != NULL ? CORBA_string_dup (uri) : CORBA_string_dup ("")); +} + static void spi_streamable_class_init (SpiStreamableClass *klass) { @@ -98,6 +277,8 @@ spi_streamable_class_init (SpiStreamableClass *klass) epv->getContentTypes = impl_accessibility_streamable_get_content_types; epv->getContent = impl_accessibility_streamable_get_content; + epv->getStream = impl_accessibility_streamable_get_stream; + epv->getURI = impl_accessibility_streamable_get_uri; } static void -- 2.7.4