NetSurf
buffer.c
Go to the documentation of this file.
1/*
2 * Copyright 2004, 2005 Richard Wilson <info@tinct.net>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <stdbool.h>
20#include <stdlib.h>
21#include <string.h>
22#include <swis.h>
23#include <oslib/colourtrans.h>
24#include <oslib/os.h>
25#include <oslib/osspriteop.h>
26#include <oslib/wimp.h>
27#include <oslib/wimpreadsysinfo.h>
28
29#include "utils/nsoption.h"
30#include "utils/log.h"
31
32#include "riscos/buffer.h"
33#include "riscos/gui.h"
34#include "riscos/tinct.h"
35#include "riscos/wimp.h"
36#include "riscos/wimputils.h"
37
38#define BUFFER_EXCLUSIVE_USER_REDRAW "Only support pure user redraw (faster)"
39//#define BUFFER_EMULATE_32BPP "Redirect to a 32bpp sprite and plot with Tinct"
40
41/** Absent from OSLib
42*/
43#ifndef osspriteop_TYPEEXPANSION
44#define osspriteop_TYPEEXPANSION ((osspriteop_mode_word) 0xFu)
45#endif
46#ifndef osspriteop_TYPE16BPP4K
47#define osspriteop_TYPE16BPP4K ((osspriteop_mode_word) 0x10u)
48#endif
49
50static void ro_gui_buffer_free(void);
51
52
53/** The buffer characteristics
54*/
55static osspriteop_area *buffer = NULL;
56static char buffer_name[12] = "scr_buffer";
57
58/** The current clip area
59*/
60static os_box clipping;
61
62/** The current save area
63*/
64static osspriteop_save_area *save_area;
65static int context0;
66static int context1;
67static int context2;
68static int context3;
69
70/** The current sprite mode
71*/
72static os_mode mode;
73
74
75/**
76 * Opens a buffer for writing to.
77 *
78 * The ro_plot_origin_ variables are updated to reflect the new screen origin,
79 * so the variables should be set before calling this function, and not
80 * changed until after ro_gui_buffer_close() has been called.
81 *
82 * \param redraw the current WIMP redraw area to buffer
83 */
84void ro_gui_buffer_open(const wimp_draw *redraw)
85{
86 int size;
87 int total_size;
88 os_coord sprite_size;
89 int bpp, word_width;
90 bool palette;
91 os_error *error;
92 int palette_size = 0;
93#ifdef BUFFER_EXCLUSIVE_USER_REDRAW
94 osspriteop_header *header;
95#endif
96
97 /* Close any open buffer
98 */
99 if (buffer)
101
102 /* Store our clipping region
103 */
104 clipping = redraw->clip;
105
106 /* Stop bad rectangles
107 */
108 if ((clipping.x1 < clipping.x0) ||
109 (clipping.y1 < clipping.y0)) {
110 NSLOG(netsurf, INFO,
111 "Invalid clipping rectangle (%i, %i) to (%i,%i)",
112 clipping.x0,
113 clipping.y0,
114 clipping.x1,
115 clipping.y1);
116 return;
117 }
118
119 /* Work out how much buffer we need
120 */
121 sprite_size.x = clipping.x1 - clipping.x0 + 1;
122 sprite_size.y = clipping.y1 - clipping.y0 + 1;
123 ro_convert_os_units_to_pixels(&sprite_size, (os_mode)-1);
124 if (sprite_size.y == 1) /* work around SpriteExtend bug */
125 sprite_size.y = 2;
126
127#ifdef BUFFER_EMULATE_32BPP
128 bpp = 5;
129 palette = false;
130#else
131 /* Get the screen depth as we can't use palettes for >8bpp
132 */
133 xos_read_mode_variable((os_mode)-1, os_MODEVAR_LOG2_BPP, &bpp, 0);
134 palette = (bpp < 4);
135#endif
136
137 /* Get our required buffer size
138 */
139 word_width = ((sprite_size.x << bpp) + 31) >> 5;
140 if (palette)
141 palette_size = ((1 << (1 << bpp)) << 3);
142 total_size = sizeof(osspriteop_area) + sizeof(osspriteop_header) +
143 (word_width * sprite_size.y * 4) + palette_size;
144 buffer = (osspriteop_area *)malloc(total_size);
145 if (!buffer) {
146 NSLOG(netsurf, INFO, "Failed to allocate memory");
148 return;
149 }
150 buffer->size = total_size;
151 buffer->first = 16;
152
153#ifdef BUFFER_EMULATE_32BPP
155#else
156 if ((error = xwimpreadsysinfo_wimp_mode(&mode)) != NULL) {
157 NSLOG(netsurf, INFO, "Error reading mode '%s'",
158 error->errmess);
160 return;
161 }
162
163 /* if we're not in a numbered screen mode then we need
164 to build a suitable sprite mode word */
165 if (mode >= (os_mode)0x100) {
166 static const ns_os_vdu_var_list vars = {
167 os_MODEVAR_LOG2_BPP,
168 {
169 os_MODEVAR_MODE_FLAGS,
170 os_MODEVAR_NCOLOUR,
171 os_MODEVAR_XEIG_FACTOR,
172 os_MODEVAR_YEIG_FACTOR,
173 os_VDUVAR_END_LIST
174 }
175 };
176 struct {
177 int log2bpp;
178 int flags;
179 int ncolour;
180 int xeig, yeig;
181 } vals;
182 int type;
183
184 error = xos_read_vdu_variables(PTR_OS_VDU_VAR_LIST(&vars), (int *)&vals);
185 if (error) {
186 NSLOG(netsurf, INFO,
187 "Error reading mode properties '%s'",
188 error->errmess);
190 return;
191 }
192
193 switch (vals.ncolour) {
194 case 1:
195 case 3:
196 case 15:
197 case 63:
198 case 255:
199 /* Paletted modes are pixel packing order agnostic */
200 type = 1 + vals.log2bpp;
201 mode = (os_mode)((type << osspriteop_TYPE_SHIFT) |
202 osspriteop_NEW_STYLE |
203 ((180 >> vals.yeig) << osspriteop_YRES_SHIFT) |
204 ((180 >> vals.xeig) << osspriteop_XRES_SHIFT));
205 break;
206 case 4095:
207 /* 16bpp 4k colours */
209 mode = (os_mode)((osspriteop_TYPEEXPANSION << osspriteop_TYPE_SHIFT) |
210 osspriteop_NEW_STYLE |
211 (vals.yeig << 6) |
212 (vals.xeig << 4) |
213 (type << 20) |
214 (vals.flags & 0xFF00));
215 break;
216 case 65535:
217 switch ((vals.flags & 0x3000) >> os_MODE_FLAG_DATA_FORMAT_SHIFT) {
218 case os_MODE_FLAG_DATA_FORMAT_RGB:
219 if (vals.flags & 0xC000) {
220 /* Non VIDC packing order */
221 if (vals.flags & os_MODE_FLAG_FULL_PALETTE)
222 type = osspriteop_TYPE16BPP64K;
223 else
224 type = osspriteop_TYPE16BPP;
225 mode = (os_mode)((osspriteop_TYPEEXPANSION << osspriteop_TYPE_SHIFT) |
226 osspriteop_NEW_STYLE |
227 (vals.yeig << 6) |
228 (vals.xeig << 4) |
229 (type << 20) |
230 (vals.flags & 0xFF00));
231 } else {
232 /* VIDC packing order */
233 if (vals.flags & os_MODE_FLAG_FULL_PALETTE)
234 type = osspriteop_TYPE16BPP64K;
235 else
236 type = osspriteop_TYPE16BPP;
237 mode = (os_mode)((type << osspriteop_TYPE_SHIFT) |
238 osspriteop_NEW_STYLE |
239 ((180 >> vals.yeig) << osspriteop_YRES_SHIFT) |
240 ((180 >> vals.xeig) << osspriteop_XRES_SHIFT));
241 }
242 break;
243 default:
244 NSLOG(netsurf, INFO,
245 "Unhandled 16bpp format from flags %d",
246 vals.flags);
248 return;
249 }
250 break;
251 case -1:
252 /* 16M colours */
253 switch ((vals.flags & 0x3000) >> os_MODE_FLAG_DATA_FORMAT_SHIFT) {
254 case os_MODE_FLAG_DATA_FORMAT_RGB:
255 if (vals.flags & 0xC000) {
256 /* Non VIDC packing order */
257 type = osspriteop_TYPE32BPP;
258 mode = (os_mode)((osspriteop_TYPEEXPANSION << osspriteop_TYPE_SHIFT) |
259 osspriteop_NEW_STYLE |
260 (vals.yeig << 6) |
261 (vals.xeig << 4) |
262 (type << 20) |
263 (vals.flags & 0xFF00));
264 } else {
265 /* VIDC packing order */
266 type = osspriteop_TYPE32BPP;
267 mode = (os_mode)((type << osspriteop_TYPE_SHIFT) |
268 osspriteop_NEW_STYLE |
269 ((180 >> vals.yeig) << osspriteop_YRES_SHIFT) |
270 ((180 >> vals.xeig) << osspriteop_XRES_SHIFT));
271 }
272 break;
273 default:
274 NSLOG(netsurf, INFO,
275 "Unhandled 32bpp data format from flags %d",
276 vals.flags);
278 return;
279 }
280 break;
281 default:
282 NSLOG(netsurf, INFO, "Unhandled NCOLOUR value %d",
283 vals.ncolour);
285 return;
286 }
287 }
288#endif
289
290#ifdef BUFFER_EXCLUSIVE_USER_REDRAW
291 /* Create the sprite manually so we don't waste time clearing the
292 background.
293 */
294 buffer->sprite_count = 1;
295 buffer->used = total_size;
296 header = (osspriteop_header *)(buffer + 1);
297 header->size = total_size - sizeof(osspriteop_area);
298 memcpy(header->name, buffer_name, 12);
299 header->width = word_width - 1;
300 header->height = sprite_size.y - 1;
301 header->left_bit = 0;
302 header->right_bit = ((sprite_size.x << bpp) - 1) & 31;
303 header->image = sizeof(osspriteop_header) + palette_size;
304 header->mask = header->image;
305 header->mode = mode;
306 if (palette)
307 xcolourtrans_read_palette((osspriteop_area *)mode,
308 (osspriteop_id)os_CURRENT_MODE,
309 (os_palette *)(header + 1), palette_size,
310 (colourtrans_palette_flags)
311 colourtrans_FLASHING_PALETTE, 0);
312#else
313 /* Read the current contents of the screen
314 */
315 buffer->sprite_count = 0;
316 buffer->used = 16;
317 if ((error = xosspriteop_get_sprite_user_coords(osspriteop_NAME,
318 buffer, buffer_name, palette,
319 clipping.x0, clipping.y0,
320 clipping.x1, clipping.y1)) != NULL) {
321 NSLOG(netsurf, INFO, "Grab error '%s'", error->errmess);
323 return;
324 }
325#endif
326 /* Allocate OS_SpriteOp save area
327 */
328 if ((error = xosspriteop_read_save_area_size(osspriteop_PTR,
329 buffer, (osspriteop_id)(buffer + 1), &size)) != NULL) {
330 NSLOG(netsurf, INFO, "Save area error '%s'", error->errmess);
332 return;
333 }
334 if ((save_area = malloc((size_t)size)) == NULL) {
336 return;
337 }
338 save_area->a[0] = 0;
339
340 /* Switch output to sprite
341 */
342 if ((error = xosspriteop_switch_output_to_sprite(osspriteop_PTR,
343 buffer, (osspriteop_id)(buffer + 1), save_area,
344 &context0, &context1, &context2, &context3)) != NULL) {
345 NSLOG(netsurf, INFO, "Switching error '%s'", error->errmess);
346 free(save_area);
348 return;
349 }
350
351 /* Emulate an origin as the FontManager doesn't respect it in
352 most cases.
353 */
356
357 /* Update the ECF origin
358 */
359 if ((error = xos_set_ecf_origin(-ro_plot_origin_x,
360 -ro_plot_origin_y)) != NULL) {
361 NSLOG(netsurf, INFO, "Invalid ECF origin: '%s'",
362 error->errmess);
363 }
364}
365
366
367/**
368 * Closes any open buffer and flushes the contents to screen
369 */
371{
372 /* Check we have an open buffer
373 */
374 if (!buffer)
375 return;
376
377 /* Remove any previous redirection
378 */
381 xosspriteop_unswitch_output(context0, context1, context2, context3);
382 free(save_area);
383
384 /* Plot the contents to screen
385 */
386 if (mode == tinct_SPRITE_MODE)
387 _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7),
388 (char *)(buffer + 1),
389 clipping.x0, clipping.y0,
390 nsoption_int(plot_fg_quality));
391 else
392 xosspriteop_put_sprite_user_coords(osspriteop_PTR,
393 buffer, (osspriteop_id)(buffer + 1),
394 clipping.x0, clipping.y0, (os_action)0);
396
397 /* Update the ECF origin
398 */
399 os_set_ecf_origin(0, 0);
400}
401
402
403/**
404 * Releases any buffer memory depending on cache constraints.
405 */
406static void ro_gui_buffer_free(void)
407{
408 free(buffer);
409 buffer = NULL;
410}
static int context1
Definition: buffer.c:66
void ro_gui_buffer_close(void)
Closes any open buffer and flushes the contents to screen.
Definition: buffer.c:370
static osspriteop_save_area * save_area
The current save area.
Definition: buffer.c:64
void ro_gui_buffer_open(const wimp_draw *redraw)
Opens a buffer for writing to.
Definition: buffer.c:84
#define osspriteop_TYPE16BPP4K
Definition: buffer.c:47
static int context2
Definition: buffer.c:67
static int context0
Definition: buffer.c:65
static int context3
Definition: buffer.c:68
static os_mode mode
The current sprite mode.
Definition: buffer.c:72
static os_box clipping
The current clip area.
Definition: buffer.c:60
static osspriteop_area * buffer
The buffer characteristics.
Definition: buffer.c:55
static char buffer_name[12]
Definition: buffer.c:56
static void ro_gui_buffer_free(void)
Releases any buffer memory depending on cache constraints.
Definition: buffer.c:406
#define osspriteop_TYPEEXPANSION
Absent from OSLib.
Definition: buffer.c:44
Screen buffering (interface).
const char * type
Definition: filetype.cpp:44
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
int ro_plot_origin_x
Definition: plotters.c:40
int ro_plot_origin_y
Definition: plotters.c:41
Interface to utility string handling.
Tinct SWI numbers and flags for version 0.11.
#define tinct_SPRITE_MODE
Definition: tinct.h:156
#define Tinct_Plot
Plots a sprite at the specified coordinates with a constant 0xff value for the alpha channel,...
Definition: tinct.h:64
Option reading and saving interface.
#define nsoption_int(OPTION)
Get the value of an integer option.
Definition: nsoption.h:313
void ro_convert_os_units_to_pixels(os_coord *os_units, os_mode mode)
Converts the supplied os_coord from OS units to pixels.
Definition: wimp.c:151
General RISC OS WIMP/OS library functions (interface).
A collection of grubby utilities for working with OSLib's wimp API.
#define PTR_OS_VDU_VAR_LIST(l)
Definition: wimputils.h:66