/* Copyright 1997 Acorn Computers Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /***************************************************/ /* File : Object.c */ /* */ /* Purpose: Handling OBJECT, APPLET and EMBED. */ /* */ /* Author : A.D.Hodgkinson */ /* */ /* History: 05-Oct-97: Created. */ /***************************************************/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include "swis.h" #include "flex.h" #include "HTMLLib.h" /* HTML library API, Which will include html2_ext.h, tags.h and struct.h */ #include "wimp.h" #include "wimplib.h" #include "event.h" #include "toolbox.h" #include "svcprint.h" #include "Global.h" #include "FromROSLib.h" #include "Utils.h" #include "Browser.h" #include "Fetch.h" /* (Which itself includes URLstat.h) */ #include "FetchHTML.h" #include "Filetypes.h" #include "Images.h" #include "Memory.h" #include "MimeMap.h" #include "MiscDefs.h" #include "PlugIn.h" #include "Redraw.h" #include "Reformat.h" #include "TokenUtils.h" #include "URLveneer.h" #include "Object.h" /* Static function prototypes */ static int object_get_token_object (browser_data * b, HStream * t); static _kernel_oserror * object_get_object_size (browser_data * b, int object, BBox * size); static _kernel_oserror * object_get_object_plugin (browser_data * b, int object, unsigned int * plugin_instance, unsigned int * plugin_task); static _kernel_oserror * object_set_object_plugin (browser_data * b, int object, unsigned int plugin_instance, unsigned int plugin_task); /*************************************************/ /* object_new_object() */ /* */ /* Adds a structure for a new Object to a */ /* browser's array of Objects. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* to add to; */ /* */ /* Pointer to a token representing */ /* the Object (OBJECT, EMBED or */ /* APPLET tag). */ /*************************************************/ _kernel_oserror * object_new_object(browser_data * b, HStream * t) { _kernel_oserror * e; const char * data; const char * type; /* If this isn't an Object token, do nothing (well, */ /* complain about it in TRACE builds). */ if (!t || t->tagno != TAG_OBJECT) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Token %08x passed to object_new_object does not represent an OBJECT, APPLET or EMBED tag", (int) t); return &erb; #endif return NULL; } /* Allocate memory for the item */ RetError(memory_set_chunk_size(b, NULL, CK_OBJB, (b->nobjects + 1) * sizeof(object_info))); /* Fill in the new item */ b->odata[b->nobjects].plugin_instance_handle = 0; b->odata[b->nobjects].plugin_task_handle = 0; b->odata[b->nobjects].token = t; /* Until this is seen by the user, open it off-screen to avoid */ /* having to send out lots of reposition calls during the main */ /* page reformat. */ b->odata[b->nobjects].x = -1; b->odata[b->nobjects].y = -1; /* Width and height initially come from the token, but if this */ /* ends up leading to a Plug-In being called, that Plug-In */ /* could ask for the size to change; hence the 'width' and */ /* 'height' fields. */ b->odata[b->nobjects].units = UNITS_PIXELS; b->odata[b->nobjects].width = t->cols; b->odata[b->nobjects].height = t->rows; /* Set up initial flags values */ b->odata[b->nobjects].isimage = 0; b->odata[b->nobjects].isplugin = 0; b->odata[b->nobjects].broadcast_sent = 0; /* Finally, increment the objects counter */ b->nobjects++; /* Now deal with data types we can handle inline */ data = HtmlOBJECTdata(t); type = HtmlOBJECTtype(t); if (data && *data && type && *type) { int filetype; RetError(mimemap_mime_to_riscos(type, &filetype)); /* Is it an image we can handle? */ if ( filetype == FileType_PNG || filetype == FileType_GIF || filetype == FileType_JPEG || filetype == FileType_TIFF || filetype == FileType_XBM || filetype == FileType_BMP ) { RetError(image_new_image(b, data, t, 0)); b->odata[b->nobjects - 1].isimage = 1; return NULL; } } /* Deal with external objects */ else { data = HtmlOBJECTclassid(t); type = HtmlOBJECTcodetype(t); if (data && type) b->odata[b->nobjects - 1].isplugin = 1; } return NULL; } /*************************************************/ /* object_discard() */ /* */ /* Discards all Objects held by a given browser. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the Objects. */ /*************************************************/ _kernel_oserror * object_discard(browser_data * b) { _kernel_oserror * e = NULL; int i; /* Close down any Plug-Ins */ for (i = 0; i < b->nobjects; i++) { if ( b->odata[i].isplugin && b->odata[i].broadcast_sent && b->odata[i].plugin_task_handle ) { e = plugin_send_plugin_close(b, b->odata[i].plugin_instance_handle, b->odata[i].plugin_task_handle); } } /* Remove the Objects */ b->nobjects = 0; memory_set_chunk_size(b, NULL, CK_OBJB, 0); return e; } /*************************************************/ /* object_get_token_object() */ /* */ /* Return the number of the Object represented */ /* in the given browser by the given token. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the Object; */ /* */ /* Pointer to a token representing */ /* the Object (OBJECT, EMBED or */ /* APPLET tag). */ /* */ /* Returns: Number of the Object from 0 to */ /* number of Objects minus 1, or -1 */ /* if the Object cannot be found. */ /*************************************************/ static int object_get_token_object(browser_data * b, HStream * t) { int found = -1; int i; /* If this isn't an Object token, do nothing (well, */ /* complain about it in TRACE builds). */ if (!t || t->tagno != TAG_OBJECT) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Token %08x passed to object_new_object does not represent an OBJECT, APPLET or EMBED tag", (int) t); show_error_ret(&erb); #endif return -1; } /* Otherwise, try to find the item */ for (i = 0; i < b->nobjects; i++) { if (b->odata[i].token == t) { found = i; break; } } return found; } /*************************************************/ /* object_get_object_size() */ /* */ /* Returns the size of a given Object. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* to add to; */ /* */ /* Number of the Object, from 0 to */ /* number of Objects minus 1; */ /* */ /* Pointer to a BBox, in which the */ /* size of the Object will be */ /* written. */ /*************************************************/ static _kernel_oserror * object_get_object_size(browser_data * b, int object, BBox * size) { /* Can't do anything without a bounding box! */ if (!size) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; strcpy(erb.errmess, "Null bounding box pointer passed to object_get_object_size"); return &erb; #endif return NULL; } /* Fill in zeros to start with */ size->xmin = size->ymin = 0; size->xmax = size->ymax = 0; /* Is this a valid object number? */ if (object < 0 || object >= b->nobjects) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Invalid object number %d for passed to object_get_object_size (browser %08x, nobjects = %d)", object, (int) b, b->nobjects); return &erb; #endif return NULL; } /* If this is an image, return through the image sizing routines */ if (b->odata[object].isimage) return image_get_token_image_size(b, b->odata[object].token, size); /* Find its size */ if (b->odata[object].units == UNITS_PIXELS) { size->xmax = b->odata[object].width * 2; /* A 'web pixel' -> 2 OS units under RISC OS */ size->ymax = b->odata[object].height * 2; } /* Don't allow zero in any direction */ if (size->xmax == 0 || size->ymax == 0) { size->xmax = ImageDefaultOSSize_X; size->ymax = ImageDefaultOSSize_Y; } return NULL; } /*************************************************/ /* object_get_token_object_size() */ /* */ /* Returns the size of a given Object. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the Object; */ /* */ /* Pointer to a token representing */ /* the Object (OBJECT, EMBED or */ /* APPLET tag); */ /* */ /* Pointer to a BBox, in which the */ /* size of the Object will be */ /* written. */ /*************************************************/ _kernel_oserror * object_get_token_object_size(browser_data * b, HStream * t, BBox * size) { return object_get_object_size(b, object_get_token_object(b, t), size); } /*************************************************/ /* object_get_token_object_position() */ /* */ /* Returns the x and y fields of the object_info */ /* structure for a given Object. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the Object; */ /* */ /* Pointer to the token representing */ /* the Object; */ /* */ /* Pointer to an int, in which the */ /* X coordinate is returned; */ /* */ /* Pointer to an int, in which the */ /* Y coordinate is returned. */ /* */ /* Returns: 1 if the object could not be */ /* found from the given token, or 0 */ /* for success. */ /* */ /* Assumes: Neither pointer is NULL. */ /*************************************************/ int object_get_token_object_position(browser_data * b, HStream * t, int * x, int * y) { int object = object_get_token_object(b, t); if (object < 0) return 1; *x = b->odata[object].x; *y = b->odata[object].y; return 0; } /*************************************************/ /* object_set_token_object_position() */ /* */ /* Sets the x and y fields of the object_info */ /* structure for a given Object, so that it may */ /* be [partially] plotted during a fetch. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the object; */ /* */ /* Pointer to the token representing */ /* the Object; */ /* */ /* X coordinate (window coords); */ /* */ /* Y coordinate (window coords). */ /* */ /* Returns: Number of the Object that was */ /* changed, or -1 if none could be */ /* found for the given token. */ /*************************************************/ int object_set_token_object_position(browser_data * b, HStream * t, int x, int y) { int object = object_get_token_object(b, t); /* If an object was found, set the x and y coordinates */ if (object >= 0) { int oldx, oldy; oldx = b->odata[object].x; oldy = b->odata[object].y; b->odata[object].x = x; b->odata[object].y = y; /* If this is is acting as an image, need to update */ /* the image structure too. */ if (b->odata[object].isimage) image_set_token_image_position(b, t, x, y); /* If this item is a Plug-In, this could be the first time we've */ /* known for sure what position the item should be plotted at; */ /* pr we may want to tell the Plug-In to move to a new position. */ if (b->odata[object].isplugin) { BBox position; show_error_ret(object_get_object_size(b, object, &position)); /* If this is the first time we've tried to set a position for */ /* the Object and a broadcast to start up an associated */ /* Plug-In has not yet been sent, send it. */ if (!b->odata[object].broadcast_sent) { if (x < 0) { /* Object position is invalid, so hide the Plug-In */ position.xmin = -position.xmax - 16; position.xmax = -16; position.ymin = position.ymax + 16; position.ymin = 16; } else { /* Object position is valid, we can place it in the right position initially */ position.xmin += x; position.ymin += y; position.xmax += x; position.ymax += y; } b->odata[object].broadcast_sent = 1; /* Don't try over and over if the first gives an error */ show_error_ret(plugin_broadcast_plugin_open(b, t, &position)); } /* If the Plug-In has been started, and the position of the Object */ /* has changed, tell the Plug-In to move. */ else if ( ( oldx != x || oldy != y ) && b->odata[object].plugin_task_handle ) { if (x < 0) { /* Object position has been invalidated, so hide the Plug-In */ position.xmin = -position.xmax - 16; position.xmax = -16; position.ymin = position.ymax + 16; position.ymin = 16; } else { /* Object position has been updated */ position.xmin += x; position.ymin += y; position.xmax += x; position.ymax += y; } /* Send the reshape message */ show_error_ret(plugin_send_original_plugin_reshape(b, b->odata[object].plugin_instance_handle, b->odata[object].plugin_task_handle, &position)); } } } return object; } /*************************************************/ /* object_get_object_plugin() */ /* */ /* Returns details of any Plug-In associated */ /* with a given Object (referenced by number). */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the Object; */ /* */ /* Number of the Object; */ /* */ /* Pointer to an int, in which the */ /* Plug-In instance handle will be */ /* written; */ /* */ /* Pointer to an int, in which the */ /* Plug-In task handle will be */ /* written, or 0 if the Object */ /* does not have an associated */ /* Plug-In or can't be found. */ /* */ /* Assumes: Either pointer may be NULL. */ /*************************************************/ static _kernel_oserror * object_get_object_plugin(browser_data * b, int object, unsigned int * plugin_instance, unsigned int * plugin_task) { /* Fill in zeros to start with */ if (plugin_instance) *plugin_instance = 0; if (plugin_task) *plugin_task = 0; /* Is this a valid object number? */ if (object < 0 || object >= b->nobjects) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Invalid object number %d passed to object_get_token_object_plugin (browser %08x, nobjects = %d)", object, (int) b, b->nobjects); return &erb; #endif return NULL; } /* If not associated with a Plug-In, exit */ if (!b->odata[object].isplugin) return NULL; /* Otherwise, return the details */ if (plugin_instance) *plugin_instance = b->odata[object].plugin_instance_handle; if (plugin_task) *plugin_task = b->odata[object].plugin_task_handle; /* Finished */ return NULL; } /*************************************************/ /* object_get_token_object_plugin() */ /* */ /* Returns details of any Plug-In associated */ /* with a given Object (referenced by token). */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the Object; */ /* */ /* Pointer to the token representing */ /* the Object; */ /* */ /* Pointer to an int, in which the */ /* Plug-In instance handle will be */ /* written; */ /* */ /* Pointer to an int, in which the */ /* Plug-In task handle will be */ /* written, or 0 if the Object */ /* does not have an associated */ /* Plug-In or can't be found. */ /* */ /* Assumes: Either pointer may be NULL. */ /*************************************************/ _kernel_oserror * object_get_token_object_plugin(browser_data * b, HStream * t, unsigned int * plugin_instance, unsigned int * plugin_task) { return object_get_object_plugin(b, object_get_token_object(b, t), plugin_instance, plugin_task); } /*************************************************/ /* object_set_object_plugin() */ /* */ /* Sets details of any Plug-In associated with */ /* a given Object (referenced by number). */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the Object; */ /* */ /* Number of the Object; */ /* */ /* Plug-In instance handle to set; */ /* */ /* Plug-In task handle to set. */ /* */ /* Assumes: Either pointer may be NULL. */ /*************************************************/ static _kernel_oserror * object_set_object_plugin(browser_data * b, int object, unsigned int plugin_instance, unsigned int plugin_task) { /* Is this a valid object number? */ if (object < 0 || object >= b->nobjects) { #ifdef TRACE erb.errnum = Utils_Error_Custom_Normal; sprintf(erb.errmess, "Invalid object number %d for passed to object_set_token_object_plugin (browser %08x, nobjects = %d)", object, (int) b, b->nobjects); return &erb; #endif return NULL; } /* If not associated with a Plug-In, exit */ if (!b->odata[object].isplugin) return NULL; /* Otherwise, set the details */ b->odata[object].plugin_instance_handle = plugin_instance; b->odata[object].plugin_task_handle = plugin_task; /* Finished */ return NULL; } /*************************************************/ /* object_set_token_object_plugin() */ /* */ /* Sets details of any Plug-In associated with */ /* a given Object (referenced by token). */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the Object - usually */ /* set as the browser instance */ /* handle for the Plug-In, so cast */ /* as an int; */ /* */ /* Pointer to the token representing */ /* the Object (usually have to */ /* remember this when the initial */ /* Message_PlugIn_Open is sent); */ /* */ /* Plug-In instance handle to set; */ /* */ /* Plug-In task handle to set. */ /* */ /* Assumes: Either pointer may be NULL. */ /*************************************************/ _kernel_oserror * object_set_token_object_plugin(unsigned int browser_instance, HStream * t, unsigned int plugin_instance, unsigned int plugin_task) { browser_data * b = (browser_data *) browser_instance; return object_set_object_plugin(b, object_get_token_object(b, t), plugin_instance, plugin_task); } /*************************************************/ /* object_redraw() */ /* */ /* Does a high level redraw of an Object, using */ /* an outline to show where the Object should be */ /* if it isn't plotted by some other method. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the Object; */ /* */ /* Pointer to a RedrawWindowBlock */ /* struct which holds information */ /* about the current redraw session; */ /* */ /* Address of the token representing */ /* the OBJECT, APPLET or EMBED tag; */ /* */ /* The X offset in window coords (so */ /* OS units) of the left hand edge */ /* of the Object; */ /* */ /* The Y offset in window coords (so */ /* OS units) of the bottom edge of */ /* the Object. */ /*************************************************/ _kernel_oserror * object_redraw(browser_data * b, WimpRedrawWindowBlock * r, HStream * token, int x, int y) { _kernel_oserror * e = NULL; int object = object_get_token_object(b, token); int plotted = 0; if (b->odata[object].isimage) { e = image_redraw(b, r, token, x, y); if (!e) plotted = 1; } if (!plotted) { /* Plot a placeholder */ BBox box; object_get_object_size(b, object, &box); box.xmin += x; box.ymin += y; box.xmax += x - box.xmin; box.ymax += y - box.ymin; box.xmin &= ~(wimpt_dx() - 1); box.ymin &= ~(wimpt_dy() - 1); redraw_draw_placeholder(b, r, &box, token, HtmlOBJECTstandby(token)); } return e; } /*************************************************/ /* object_token_is_image() */ /* */ /* Finds out whether an Object is acting as an */ /* an inline image or not. */ /* */ /* Parameters: Pointer to a browser_data struct */ /* relevant to the object; */ /* */ /* Pointer to the token representing */ /* the Object. */ /* */ /* Returns: 1 if the Object is acting as an */ /* inline image, else 0. */ /*************************************************/ int object_token_is_image(browser_data * b, HStream * t) { int object = object_get_token_object(b, t); if (object < 0 || object >= b->nobjects) return 0; else return !!b->odata[object].isimage; }