/* 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); /*************************************************/ /* 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; /* 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].browser_instance_handle = 0; 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->rows; b->odata[b->nobjects].height = t->cols; /* Set up initial flags values */ b->odata[b->nobjects].isimage = 0; /* Finally, increment the objects counter */ b->nobjects++; /* Now deal with data types we can handle inline */ if ( HtmlOBJECTdata(t) && HtmlOBJECTtype(t) ) { const char * data = HtmlOBJECTdata(t); const char * type = HtmlOBJECTtype(t); if (*data) { 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; } } } /* Finally deal with other objects */ 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) { b->nobjects = 0; return memory_set_chunk_size(b, NULL, CK_OBJB, 0); } /*************************************************/ /* 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 Objects; */ /* */ /* 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 */ /* to add to; */ /* */ /* 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) { 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); } return object; } /*************************************************/ /* 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); if (box.xmax > 8 && box.ymax > 8) { /* xmin, ymin hold the bottom left hand corner coordinates, whilst */ /* xmax, ymax hold the width and height. The adjustments are to */ /* account for the way the bbc_rectanglefill function works; e.g., */ /* to get a width of 4 OS units, ask for 3 (as it adds this to the */ /* x coordinate and treats it as an inclusive x coordinate max). */ /* There are corrections to plot 2 OS units inside of the real */ /* bounding box (looks better when images touch each other) and to */ /* get the darker sides of the 'slabbed in' box overlapping the */ /* lighter sides by the right amount. */ redraw_set_colour(Redraw_Colour_AlmostWhite); bbc_rectanglefill(box.xmin + 2, box.ymin + 2, box.xmax - 5, 3); bbc_rectanglefill(box.xmax + box.xmin - 6, box.ymin + 2, 3, box.ymax - 5); redraw_set_colour(Redraw_Colour_MidGrey); bbc_rectanglefill(box.xmin + 2, box.ymax + box.ymin - 6, box.xmax - 7, 3); bbc_rectanglefill(box.xmin + 2, box.ymin + 4, 3, box.ymax - 7); } else { if (box.xmax < 2) box.xmax = 2; if (box.ymax < 2) box.ymax = 2; redraw_set_colour(0); bbc_rectangle(box.xmin,box.ymin,box.xmax - 1,box.ymax - 1); } } 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; }