2008-11-13 11:07:45 +00:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it either under the terms of the GNU Lesser General Public
|
|
|
|
|
* License version 2.1 as published by the Free Software Foundation
|
|
|
|
|
* (the "LGPL") or, at your option, under the terms of the Mozilla
|
|
|
|
|
* Public License Version 1.1 (the "MPL"). If you do not alter this
|
|
|
|
|
* notice, a recipient may use your version of this file under either
|
|
|
|
|
* the MPL or the LGPL.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the LGPL along with this library
|
|
|
|
|
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
|
2010-04-27 10:17:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
|
2008-11-13 11:07:45 +00:00
|
|
|
* You should have received a copy of the MPL along with this library
|
|
|
|
|
* in the file COPYING-MPL-1.1
|
|
|
|
|
*
|
|
|
|
|
* The contents of this file are subject to the Mozilla Public License
|
|
|
|
|
* Version 1.1 (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.mozilla.org/MPL/
|
|
|
|
|
*
|
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
|
|
|
|
|
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
|
|
|
|
|
* the specific language governing rights and limitations.
|
|
|
|
|
*
|
|
|
|
|
* The Original Code is the cairo graphics library.
|
|
|
|
|
*
|
|
|
|
|
* The Initial Developer of the Original Code is Chris Wilson.
|
|
|
|
|
*
|
|
|
|
|
* Contributor(s):
|
|
|
|
|
* Chris Wilson <chris@chris-wilson.co.uk>
|
|
|
|
|
*/
|
|
|
|
|
|
2015-06-16 15:05:54 -07:00
|
|
|
#include "config.h"
|
|
|
|
|
|
2008-11-13 11:07:45 +00:00
|
|
|
#include "cairo-script-private.h"
|
|
|
|
|
|
2009-05-07 14:11:12 +01:00
|
|
|
#include <limits.h> /* INT_MAX */
|
|
|
|
|
#include <math.h> /* pow */
|
2008-11-13 11:07:45 +00:00
|
|
|
#include <stdio.h> /* EOF */
|
2011-06-22 14:40:23 +02:00
|
|
|
#include <stdint.h> /* for {INT,UINT}*_{MIN,MAX} */
|
2013-01-04 17:32:46 +00:00
|
|
|
#include <stdlib.h> /* malloc/free */
|
2008-11-13 11:07:45 +00:00
|
|
|
#include <string.h> /* memset */
|
2009-07-03 00:40:32 +01:00
|
|
|
#include <assert.h>
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
#include <zlib.h>
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2013-01-04 17:32:46 +00:00
|
|
|
#if HAVE_LZO
|
2024-09-04 22:25:07 -07:00
|
|
|
#include <lzo2a.h>
|
2013-01-04 17:32:46 +00:00
|
|
|
#endif
|
|
|
|
|
|
2009-07-04 18:32:57 +01:00
|
|
|
#define DEBUG_SCAN 0
|
|
|
|
|
|
2010-02-05 22:30:05 +01:00
|
|
|
#if WORDS_BIGENDIAN
|
|
|
|
|
#define le16(x) bswap_16 (x)
|
|
|
|
|
#define le32(x) bswap_32 (x)
|
|
|
|
|
#define be16(x) x
|
|
|
|
|
#define be32(x) x
|
|
|
|
|
#define to_be32(x) x
|
|
|
|
|
#else
|
|
|
|
|
#define le16(x) x
|
|
|
|
|
#define le32(x) x
|
|
|
|
|
#define be16(x) bswap_16 (x)
|
|
|
|
|
#define be32(x) bswap_32 (x)
|
|
|
|
|
#define to_be32(x) bswap_32 (x)
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-11-13 11:07:45 +00:00
|
|
|
/*
|
|
|
|
|
* whitespace:
|
|
|
|
|
* 0 - nul
|
|
|
|
|
* 9 - tab
|
|
|
|
|
* A - LF
|
|
|
|
|
* C - FF
|
|
|
|
|
* D - CR
|
|
|
|
|
*
|
|
|
|
|
* syntax delimiters
|
|
|
|
|
* ( = 28, ) = 29 - literal strings
|
|
|
|
|
* < = 3C, > = 3E - hex/base85 strings, dictionary name
|
|
|
|
|
* [ = 5B, ] = 5D - array
|
|
|
|
|
* { = 7B, } = 7C - procedure
|
|
|
|
|
* / = 5C - literal marker
|
|
|
|
|
* % = 25 - comment
|
|
|
|
|
*/
|
|
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
static void
|
|
|
|
|
fprintf_obj (FILE *stream, csi_t *ctx, const csi_object_t *obj)
|
|
|
|
|
{
|
|
|
|
|
switch (csi_object_get_type (obj)) {
|
|
|
|
|
case CSI_OBJECT_TYPE_NULL:
|
|
|
|
|
fprintf (stream, "NULL\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* atomics */
|
|
|
|
|
case CSI_OBJECT_TYPE_BOOLEAN:
|
|
|
|
|
fprintf (stream, "boolean: %s\n",
|
|
|
|
|
obj->datum.boolean ? "true" : "false");
|
|
|
|
|
break;
|
|
|
|
|
case CSI_OBJECT_TYPE_INTEGER:
|
|
|
|
|
fprintf (stream, "integer: %ld\n", obj->datum.integer);
|
|
|
|
|
break;
|
|
|
|
|
case CSI_OBJECT_TYPE_MARK:
|
|
|
|
|
fprintf (stream, "mark\n");
|
|
|
|
|
break;
|
|
|
|
|
case CSI_OBJECT_TYPE_NAME:
|
|
|
|
|
fprintf (stream, "name: %s\n", (char *) obj->datum.name);
|
|
|
|
|
break;
|
|
|
|
|
case CSI_OBJECT_TYPE_OPERATOR:
|
|
|
|
|
fprintf (stream, "operator: %p\n", obj->datum.ptr);
|
|
|
|
|
break;
|
|
|
|
|
case CSI_OBJECT_TYPE_REAL:
|
|
|
|
|
fprintf (stream, "real: %g\n", obj->datum.real);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* compound */
|
|
|
|
|
case CSI_OBJECT_TYPE_ARRAY:
|
|
|
|
|
fprintf (stream, "array\n");
|
|
|
|
|
break;
|
|
|
|
|
case CSI_OBJECT_TYPE_DICTIONARY:
|
|
|
|
|
fprintf (stream, "dictionary\n");
|
|
|
|
|
break;
|
|
|
|
|
case CSI_OBJECT_TYPE_FILE:
|
|
|
|
|
fprintf (stream, "file\n");
|
|
|
|
|
break;
|
|
|
|
|
case CSI_OBJECT_TYPE_MATRIX:
|
|
|
|
|
fprintf (stream, "matrix: [%g %g %g %g %g %g]\n",
|
|
|
|
|
obj->datum.matrix->matrix.xx,
|
|
|
|
|
obj->datum.matrix->matrix.yx,
|
|
|
|
|
obj->datum.matrix->matrix.xy,
|
|
|
|
|
obj->datum.matrix->matrix.yy,
|
|
|
|
|
obj->datum.matrix->matrix.x0,
|
|
|
|
|
obj->datum.matrix->matrix.y0);
|
|
|
|
|
break;
|
|
|
|
|
case CSI_OBJECT_TYPE_STRING:
|
2013-01-04 17:32:46 +00:00
|
|
|
fprintf (stream, "string: len=%ld, defate=%ld, method=%d\n",
|
|
|
|
|
obj->datum.string->len, obj->datum.string->deflate, obj->datum.string->method);
|
2009-07-03 00:40:32 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* cairo */
|
|
|
|
|
case CSI_OBJECT_TYPE_CONTEXT:
|
|
|
|
|
fprintf (stream, "context\n");
|
|
|
|
|
break;
|
|
|
|
|
case CSI_OBJECT_TYPE_FONT:
|
|
|
|
|
fprintf (stream, "font\n");
|
|
|
|
|
break;
|
|
|
|
|
case CSI_OBJECT_TYPE_PATTERN:
|
|
|
|
|
fprintf (stream, "pattern\n");
|
|
|
|
|
break;
|
|
|
|
|
case CSI_OBJECT_TYPE_SCALED_FONT:
|
|
|
|
|
fprintf (stream, "scaled-font\n");
|
|
|
|
|
break;
|
|
|
|
|
case CSI_OBJECT_TYPE_SURFACE:
|
|
|
|
|
fprintf (stream, "surface\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* takes ownership of obj */
|
|
|
|
|
static inline csi_status_t
|
|
|
|
|
scan_push (csi_t *ctx, csi_object_t *obj)
|
|
|
|
|
{
|
|
|
|
|
return ctx->scanner.push (ctx, obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline csi_status_t
|
|
|
|
|
scan_execute (csi_t *ctx, csi_object_t *obj)
|
|
|
|
|
{
|
|
|
|
|
return ctx->scanner.execute (ctx, obj);
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-13 11:07:45 +00:00
|
|
|
static cairo_status_t
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_init (csi_t *ctx, csi_buffer_t *buffer)
|
2008-11-13 11:07:45 +00:00
|
|
|
{
|
2009-06-28 00:48:05 +01:00
|
|
|
cairo_status_t status = CSI_STATUS_SUCCESS;
|
|
|
|
|
|
2008-11-13 11:07:45 +00:00
|
|
|
buffer->size = 16384;
|
|
|
|
|
buffer->base = _csi_alloc (ctx, buffer->size);
|
|
|
|
|
if (_csi_unlikely (buffer->base == NULL)) {
|
2009-06-28 00:48:05 +01:00
|
|
|
status = _csi_error (CSI_STATUS_NO_MEMORY);
|
2008-11-13 11:07:45 +00:00
|
|
|
buffer->size = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer->ptr = buffer->base;
|
|
|
|
|
buffer->end = buffer->base + buffer->size;
|
|
|
|
|
|
2009-06-28 00:48:05 +01:00
|
|
|
return status;
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_fini (csi_t *ctx, csi_buffer_t *buffer)
|
2008-11-13 11:07:45 +00:00
|
|
|
{
|
|
|
|
|
_csi_free (ctx, buffer->base);
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
static void
|
2009-06-28 00:48:05 +01:00
|
|
|
_buffer_grow (csi_t *ctx, csi_scanner_t *scan)
|
2008-11-13 11:07:45 +00:00
|
|
|
{
|
|
|
|
|
int newsize;
|
|
|
|
|
int offset;
|
|
|
|
|
char *base;
|
|
|
|
|
|
2009-06-28 00:48:05 +01:00
|
|
|
if (_csi_unlikely (scan->buffer.size > INT_MAX / 2))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_NO_MEMORY));
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-06-28 00:48:05 +01:00
|
|
|
offset = scan->buffer.ptr - scan->buffer.base;
|
|
|
|
|
newsize = scan->buffer.size * 2;
|
|
|
|
|
base = _csi_realloc (ctx, scan->buffer.base, newsize);
|
2008-11-13 11:07:45 +00:00
|
|
|
if (_csi_unlikely (base == NULL))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_NO_MEMORY));
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-06-28 00:48:05 +01:00
|
|
|
scan->buffer.base = base;
|
|
|
|
|
scan->buffer.ptr = base + offset;
|
|
|
|
|
scan->buffer.end = base + newsize;
|
|
|
|
|
scan->buffer.size = newsize;
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
2009-06-28 00:48:05 +01:00
|
|
|
static inline void
|
|
|
|
|
buffer_check (csi_t *ctx, csi_scanner_t *scan, int count)
|
2008-11-13 11:07:45 +00:00
|
|
|
{
|
2009-06-28 00:48:05 +01:00
|
|
|
if (_csi_unlikely (scan->buffer.ptr + count > scan->buffer.end))
|
|
|
|
|
_buffer_grow (ctx, scan);
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_add (csi_buffer_t *buffer, int c)
|
2008-11-13 11:07:45 +00:00
|
|
|
{
|
|
|
|
|
*buffer->ptr++ = c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_reset (csi_buffer_t *buffer)
|
2008-11-13 11:07:45 +00:00
|
|
|
{
|
|
|
|
|
buffer->ptr = buffer->base;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
token_start (csi_scanner_t *scan)
|
|
|
|
|
{
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_reset (&scan->buffer);
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
token_add (csi_t *ctx, csi_scanner_t *scan, int c)
|
|
|
|
|
{
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_check (ctx, scan, 1);
|
|
|
|
|
buffer_add (&scan->buffer, c);
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
token_add_unchecked (csi_scanner_t *scan, int c)
|
|
|
|
|
{
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_add (&scan->buffer, c);
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
2009-07-28 09:32:36 +01:00
|
|
|
csi_boolean_t
|
|
|
|
|
_csi_parse_number (csi_object_t *obj, const char *s, int len)
|
2008-11-13 11:07:45 +00:00
|
|
|
{
|
|
|
|
|
int radix = 0;
|
|
|
|
|
long long mantissa = 0;
|
|
|
|
|
int exponent = 0;
|
|
|
|
|
int sign = 1;
|
|
|
|
|
int decimal = -1;
|
|
|
|
|
int exponent_sign = 0;
|
|
|
|
|
const char * const end = s + len;
|
|
|
|
|
|
|
|
|
|
switch (*s) {
|
|
|
|
|
case '0':
|
|
|
|
|
case '1':
|
|
|
|
|
case '2':
|
|
|
|
|
case '3':
|
|
|
|
|
case '4':
|
|
|
|
|
case '5':
|
|
|
|
|
case '6':
|
|
|
|
|
case '7':
|
|
|
|
|
case '8':
|
|
|
|
|
case '9':
|
|
|
|
|
mantissa = *s - '0';
|
|
|
|
|
case '+':
|
|
|
|
|
break;
|
|
|
|
|
case '-':
|
|
|
|
|
sign = -1;
|
|
|
|
|
break;
|
|
|
|
|
case '.':
|
|
|
|
|
decimal = 0;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (++s < end) {
|
|
|
|
|
if (*s < '0') {
|
|
|
|
|
if (*s == '.') {
|
2009-05-26 08:53:45 +01:00
|
|
|
if (_csi_unlikely (radix))
|
2008-11-13 11:07:45 +00:00
|
|
|
return FALSE;
|
2009-05-26 08:53:45 +01:00
|
|
|
if (_csi_unlikely (decimal != -1))
|
2008-11-13 11:07:45 +00:00
|
|
|
return FALSE;
|
2009-05-26 08:53:45 +01:00
|
|
|
if (_csi_unlikely (exponent_sign))
|
2008-11-13 11:07:45 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
decimal = 0;
|
|
|
|
|
} else if (*s == '!') {
|
2009-05-26 08:53:45 +01:00
|
|
|
if (_csi_unlikely (radix))
|
2008-11-13 11:07:45 +00:00
|
|
|
return FALSE;
|
2009-05-26 08:53:45 +01:00
|
|
|
if (_csi_unlikely (decimal != -1))
|
2008-11-13 11:07:45 +00:00
|
|
|
return FALSE;
|
2009-05-26 08:53:45 +01:00
|
|
|
if (_csi_unlikely (exponent_sign))
|
2008-11-13 11:07:45 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
radix = mantissa;
|
|
|
|
|
mantissa = 0;
|
|
|
|
|
|
2009-05-26 08:53:45 +01:00
|
|
|
if (_csi_unlikely (radix < 2 || radix > 36))
|
2008-11-13 11:07:45 +00:00
|
|
|
return FALSE;
|
|
|
|
|
} else
|
|
|
|
|
return FALSE;
|
|
|
|
|
} else if (*s <= '9') {
|
|
|
|
|
int v = *s - '0';
|
2009-05-26 08:53:45 +01:00
|
|
|
if (_csi_unlikely (radix && v >= radix))
|
2008-11-13 11:07:45 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (exponent_sign) {
|
|
|
|
|
exponent = 10 * exponent + v;
|
|
|
|
|
} else {
|
|
|
|
|
if (radix)
|
|
|
|
|
mantissa = radix * mantissa + v;
|
|
|
|
|
else
|
|
|
|
|
mantissa = 10 * mantissa + v;
|
|
|
|
|
if (decimal != -1)
|
|
|
|
|
decimal++;
|
|
|
|
|
}
|
|
|
|
|
} else if (*s == 'E' || * s== 'e') {
|
|
|
|
|
if (radix == 0) {
|
2009-05-26 08:53:45 +01:00
|
|
|
if (_csi_unlikely (s + 1 == end))
|
2008-11-13 11:07:45 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
exponent_sign = 1;
|
|
|
|
|
if (s[1] == '-') {
|
|
|
|
|
exponent_sign = -1;
|
|
|
|
|
s++;
|
|
|
|
|
} else if (s[1] == '+')
|
|
|
|
|
s++;
|
|
|
|
|
} else {
|
|
|
|
|
int v = 0xe;
|
|
|
|
|
|
2009-05-26 08:53:45 +01:00
|
|
|
if (_csi_unlikely (v >= radix))
|
2008-11-13 11:07:45 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
mantissa = radix * mantissa + v;
|
|
|
|
|
}
|
|
|
|
|
} else if (*s < 'A') {
|
|
|
|
|
return FALSE;
|
|
|
|
|
} else if (*s <= 'Z') {
|
|
|
|
|
int v = *s - 'A' + 0xA;
|
|
|
|
|
|
2009-05-26 08:53:45 +01:00
|
|
|
if (_csi_unlikely (v >= radix))
|
2008-11-13 11:07:45 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
mantissa = radix * mantissa + v;
|
|
|
|
|
} else if (*s < 'a') {
|
|
|
|
|
return FALSE;
|
|
|
|
|
} else if (*s <= 'z') {
|
|
|
|
|
int v = *s - 'a' + 0xa;
|
|
|
|
|
|
2009-05-26 08:53:45 +01:00
|
|
|
if (_csi_unlikely (v >= radix))
|
2008-11-13 11:07:45 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
mantissa = radix * mantissa + v;
|
|
|
|
|
} else
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (exponent_sign || decimal != -1) {
|
|
|
|
|
if (mantissa == 0) {
|
|
|
|
|
obj->type = CSI_OBJECT_TYPE_REAL;
|
|
|
|
|
obj->datum.real = 0.;
|
|
|
|
|
return TRUE;
|
|
|
|
|
} else {
|
|
|
|
|
int e;
|
|
|
|
|
double v;
|
|
|
|
|
|
|
|
|
|
v = mantissa;
|
|
|
|
|
e = exponent * exponent_sign;
|
|
|
|
|
if (decimal != -1)
|
|
|
|
|
e -= decimal;
|
2009-05-26 08:53:45 +01:00
|
|
|
switch (e) {
|
|
|
|
|
case -7: v *= 0.0000001; break;
|
|
|
|
|
case -6: v *= 0.000001; break;
|
|
|
|
|
case -5: v *= 0.00001; break;
|
|
|
|
|
case -4: v *= 0.0001; break;
|
|
|
|
|
case -3: v *= 0.001; break;
|
|
|
|
|
case -2: v *= 0.01; break;
|
|
|
|
|
case -1: v *= 0.1; break;
|
|
|
|
|
case 0: break;
|
|
|
|
|
case 1: v *= 10; break;
|
|
|
|
|
case 2: v *= 100; break;
|
|
|
|
|
case 3: v *= 1000; break;
|
|
|
|
|
case 4: v *= 10000; break;
|
|
|
|
|
case 5: v *= 100000; break;
|
|
|
|
|
case 6: v *= 1000000; break;
|
|
|
|
|
default:
|
|
|
|
|
v *= pow (10, e); /* XXX */
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
obj->type = CSI_OBJECT_TYPE_REAL;
|
|
|
|
|
obj->datum.real = sign * v;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
obj->type = CSI_OBJECT_TYPE_INTEGER;
|
|
|
|
|
obj->datum.integer = sign * mantissa;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
token_end (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
|
|
|
|
|
{
|
2009-06-28 00:48:05 +01:00
|
|
|
cairo_status_t status;
|
2008-11-13 11:07:45 +00:00
|
|
|
char *s;
|
|
|
|
|
csi_object_t obj;
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Any token that consists entirely of regular characters and
|
|
|
|
|
* cannot be interpreted as a number is treated as a name object
|
|
|
|
|
* (more precisely, an executable name). All characters except
|
|
|
|
|
* delimiters and white-space characters can appear in names,
|
|
|
|
|
* including characters ordinarily considered to be punctuation.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (_csi_unlikely (scan->buffer.ptr == scan->buffer.base))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
s = scan->buffer.base;
|
|
|
|
|
len = scan->buffer.ptr - scan->buffer.base;
|
|
|
|
|
|
2009-08-11 21:26:11 +01:00
|
|
|
if (_csi_likely (! scan->bind)) {
|
|
|
|
|
if (s[0] == '{') { /* special case procedures */
|
|
|
|
|
if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) {
|
|
|
|
|
status = _csi_stack_push (ctx,
|
|
|
|
|
&scan->procedure_stack,
|
|
|
|
|
&scan->build_procedure);
|
|
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2009-08-11 21:26:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = csi_array_new (ctx, 0, &scan->build_procedure);
|
2009-06-28 00:48:05 +01:00
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2009-06-28 00:48:05 +01:00
|
|
|
|
2009-08-11 21:26:11 +01:00
|
|
|
scan->build_procedure.type |= CSI_OBJECT_ATTR_EXECUTABLE;
|
|
|
|
|
return;
|
|
|
|
|
} else if (s[0] == '}') {
|
|
|
|
|
if (_csi_unlikely
|
|
|
|
|
(scan->build_procedure.type == CSI_OBJECT_TYPE_NULL))
|
|
|
|
|
{
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2009-08-11 21:26:11 +01:00
|
|
|
}
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-08-11 21:26:11 +01:00
|
|
|
if (scan->procedure_stack.len) {
|
|
|
|
|
csi_object_t *next;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-08-11 21:26:11 +01:00
|
|
|
next = _csi_stack_peek (&scan->procedure_stack, 0);
|
|
|
|
|
status = csi_array_append (ctx, next->datum.array,
|
|
|
|
|
&scan->build_procedure);
|
|
|
|
|
scan->build_procedure = *next;
|
|
|
|
|
scan->procedure_stack.len--;
|
|
|
|
|
} else {
|
|
|
|
|
status = scan_push (ctx, &scan->build_procedure);
|
|
|
|
|
scan->build_procedure.type = CSI_OBJECT_TYPE_NULL;
|
|
|
|
|
}
|
|
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2009-06-28 00:48:05 +01:00
|
|
|
|
2009-08-11 21:26:11 +01:00
|
|
|
return;
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (s[0] == '/') {
|
|
|
|
|
if (len >= 2 && s[1] == '/') { /* substituted name */
|
2009-06-28 00:48:05 +01:00
|
|
|
status = csi_name_new (ctx, &obj, s + 2, len - 2);
|
|
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-06-28 00:48:05 +01:00
|
|
|
status = _csi_name_lookup (ctx, obj.datum.name, &obj);
|
2008-11-13 11:07:45 +00:00
|
|
|
} else { /* literal name */
|
2009-06-28 00:48:05 +01:00
|
|
|
status = csi_name_new (ctx, &obj, s + 1, len - 1);
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
2009-06-28 00:48:05 +01:00
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2008-11-13 11:07:45 +00:00
|
|
|
} else {
|
2009-07-28 09:32:36 +01:00
|
|
|
if (! _csi_parse_number (&obj, s, len)) {
|
2009-06-28 00:48:05 +01:00
|
|
|
status = csi_name_new (ctx, &obj, s, len);
|
|
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2009-06-28 00:48:05 +01:00
|
|
|
|
2008-11-13 11:07:45 +00:00
|
|
|
obj.type |= CSI_OBJECT_ATTR_EXECUTABLE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* consume whitespace after token, before calling the interpreter */
|
|
|
|
|
if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) {
|
2009-06-28 00:48:05 +01:00
|
|
|
status = csi_array_append (ctx,
|
|
|
|
|
scan->build_procedure.datum.array,
|
|
|
|
|
&obj);
|
2008-11-13 11:07:45 +00:00
|
|
|
} else if (obj.type & CSI_OBJECT_ATTR_EXECUTABLE) {
|
2009-07-03 00:40:32 +01:00
|
|
|
status = scan_execute (ctx, &obj);
|
|
|
|
|
csi_object_free (ctx, &obj);
|
2009-06-28 00:48:05 +01:00
|
|
|
} else {
|
2009-07-03 00:40:32 +01:00
|
|
|
status = scan_push (ctx, &obj);
|
2009-06-28 00:48:05 +01:00
|
|
|
}
|
|
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
string_add (csi_t *ctx, csi_scanner_t *scan, int c)
|
|
|
|
|
{
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_check (ctx, scan, 1);
|
|
|
|
|
buffer_add (&scan->buffer, c);
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
string_end (csi_t *ctx, csi_scanner_t *scan)
|
|
|
|
|
{
|
|
|
|
|
csi_object_t obj;
|
2009-06-28 00:48:05 +01:00
|
|
|
cairo_status_t status;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-06-28 00:48:05 +01:00
|
|
|
status = csi_string_new (ctx,
|
|
|
|
|
&obj,
|
|
|
|
|
scan->buffer.base,
|
|
|
|
|
scan->buffer.ptr - scan->buffer.base);
|
|
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
|
2009-06-28 00:48:05 +01:00
|
|
|
status = csi_array_append (ctx,
|
|
|
|
|
scan->build_procedure.datum.array,
|
|
|
|
|
&obj);
|
2008-11-13 11:07:45 +00:00
|
|
|
else
|
2009-07-03 00:40:32 +01:00
|
|
|
status = scan_push (ctx, &obj);
|
2009-06-28 00:48:05 +01:00
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
hex_value (int c)
|
|
|
|
|
{
|
|
|
|
|
if (c < '0')
|
|
|
|
|
return EOF;
|
|
|
|
|
if (c <= '9')
|
|
|
|
|
return c - '0';
|
|
|
|
|
c |= 32;
|
|
|
|
|
if (c < 'a')
|
|
|
|
|
return EOF;
|
|
|
|
|
if (c <= 'f')
|
|
|
|
|
return c - 'a' + 0xa;
|
|
|
|
|
return EOF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
hex_add (csi_t *ctx, csi_scanner_t *scan, int c)
|
|
|
|
|
{
|
|
|
|
|
if (scan->accumulator_count == 0) {
|
|
|
|
|
scan->accumulator |= hex_value (c) << 4;
|
|
|
|
|
scan->accumulator_count = 1;
|
|
|
|
|
} else {
|
|
|
|
|
scan->accumulator |= hex_value (c) << 0;
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_check (ctx, scan, 1);
|
|
|
|
|
buffer_add (&scan->buffer, scan->accumulator);
|
|
|
|
|
|
2008-11-13 11:07:45 +00:00
|
|
|
scan->accumulator = 0;
|
|
|
|
|
scan->accumulator_count = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
hex_end (csi_t *ctx, csi_scanner_t *scan)
|
|
|
|
|
{
|
|
|
|
|
csi_object_t obj;
|
2009-06-28 00:48:05 +01:00
|
|
|
cairo_status_t status;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
if (scan->accumulator_count)
|
|
|
|
|
hex_add (ctx, scan, '0');
|
|
|
|
|
|
2009-06-28 00:48:05 +01:00
|
|
|
status = csi_string_new (ctx,
|
|
|
|
|
&obj,
|
|
|
|
|
scan->buffer.base,
|
|
|
|
|
scan->buffer.ptr - scan->buffer.base);
|
|
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
|
2009-06-28 00:48:05 +01:00
|
|
|
status = csi_array_append (ctx,
|
|
|
|
|
scan->build_procedure.datum.array,
|
|
|
|
|
&obj);
|
2008-11-13 11:07:45 +00:00
|
|
|
else
|
2009-07-03 00:40:32 +01:00
|
|
|
status = scan_push (ctx, &obj);
|
2009-06-28 00:48:05 +01:00
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
base85_add (csi_t *ctx, csi_scanner_t *scan, int c)
|
|
|
|
|
{
|
|
|
|
|
if (c == 'z') {
|
2009-06-28 00:48:05 +01:00
|
|
|
if (_csi_unlikely (scan->accumulator_count != 0))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2009-06-28 00:48:05 +01:00
|
|
|
|
|
|
|
|
buffer_check (ctx, scan, 4);
|
|
|
|
|
buffer_add (&scan->buffer, 0);
|
|
|
|
|
buffer_add (&scan->buffer, 0);
|
|
|
|
|
buffer_add (&scan->buffer, 0);
|
|
|
|
|
buffer_add (&scan->buffer, 0);
|
2008-11-13 11:07:45 +00:00
|
|
|
} else if (_csi_unlikely (c < '!' || c > 'u')) {
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2008-11-13 11:07:45 +00:00
|
|
|
} else {
|
|
|
|
|
scan->accumulator = scan->accumulator*85 + c - '!';
|
|
|
|
|
if (++scan->accumulator_count == 5) {
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_check (ctx, scan, 4);
|
|
|
|
|
buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff);
|
|
|
|
|
buffer_add (&scan->buffer, (scan->accumulator >> 16) & 0xff);
|
|
|
|
|
buffer_add (&scan->buffer, (scan->accumulator >> 8) & 0xff);
|
|
|
|
|
buffer_add (&scan->buffer, (scan->accumulator >> 0) & 0xff);
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
scan->accumulator = 0;
|
|
|
|
|
scan->accumulator_count = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
base85_end (csi_t *ctx, csi_scanner_t *scan, cairo_bool_t deflate)
|
2008-11-13 11:07:45 +00:00
|
|
|
{
|
|
|
|
|
csi_object_t obj;
|
2009-06-28 00:48:05 +01:00
|
|
|
cairo_status_t status;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_check (ctx, scan, 4);
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
switch (scan->accumulator_count) {
|
|
|
|
|
case 0:
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
scan->accumulator = scan->accumulator * (85*85*85) + 85*85*85 -1;
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
scan->accumulator = scan->accumulator * (85*85) + 85*85 -1;
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff);
|
|
|
|
|
buffer_add (&scan->buffer, (scan->accumulator >> 16) & 0xff);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
scan->accumulator = scan->accumulator * 85 + 84;
|
2009-06-28 00:48:05 +01:00
|
|
|
buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff);
|
|
|
|
|
buffer_add (&scan->buffer, (scan->accumulator >> 16) & 0xff);
|
|
|
|
|
buffer_add (&scan->buffer, (scan->accumulator >> 8) & 0xff);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
if (deflate) {
|
2010-02-05 22:30:05 +01:00
|
|
|
uLongf len = be32 (*(uint32_t *) scan->buffer.base);
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
Bytef *source = (Bytef *) (scan->buffer.base + sizeof (uint32_t));
|
|
|
|
|
|
|
|
|
|
status = csi_string_deflate_new (ctx, &obj,
|
|
|
|
|
source,
|
|
|
|
|
(Bytef *) scan->buffer.ptr - source,
|
|
|
|
|
len);
|
|
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
} else {
|
|
|
|
|
status = csi_string_new (ctx,
|
|
|
|
|
&obj,
|
|
|
|
|
scan->buffer.base,
|
|
|
|
|
scan->buffer.ptr - scan->buffer.base);
|
|
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
}
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
|
2009-06-28 00:48:05 +01:00
|
|
|
status = csi_array_append (ctx,
|
|
|
|
|
scan->build_procedure.datum.array,
|
|
|
|
|
&obj);
|
2008-11-13 11:07:45 +00:00
|
|
|
else
|
2009-07-03 00:40:32 +01:00
|
|
|
status = scan_push (ctx, &obj);
|
2009-06-28 00:48:05 +01:00
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2009-07-03 00:40:32 +01:00
|
|
|
}
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-08-18 14:25:25 +01:00
|
|
|
static void
|
|
|
|
|
base64_add (csi_t *ctx, csi_scanner_t *scan, int c)
|
|
|
|
|
{
|
|
|
|
|
int val;
|
|
|
|
|
|
|
|
|
|
/* Convert Base64 character to its 6 bit nibble */
|
|
|
|
|
val = scan->accumulator;
|
|
|
|
|
if (c =='/') {
|
|
|
|
|
val = (val << 6) | 63;
|
|
|
|
|
} else if (c =='+') {
|
|
|
|
|
val = (val << 6) | 62;
|
|
|
|
|
} else if (c >='A' && c <='Z') {
|
|
|
|
|
val = (val << 6) | (c -'A');
|
|
|
|
|
} else if (c >='a' && c <='z') {
|
|
|
|
|
val = (val << 6) | (c -'a' + 26);
|
|
|
|
|
} else if (c >='0' && c <='9') {
|
|
|
|
|
val = (val << 6) | (c -'0' + 52);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer_check (ctx, scan, 1);
|
|
|
|
|
switch (scan->accumulator_count++) {
|
|
|
|
|
case 0:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
buffer_add (&scan->buffer, (val >> 4) & 0xFF);
|
|
|
|
|
val &= 0xF;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
buffer_add (&scan->buffer, (val >> 2) & 0xFF);
|
|
|
|
|
val &= 0x3;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
|
buffer_add (&scan->buffer, (val >> 0) & 0xFF);
|
|
|
|
|
scan->accumulator_count = 0;
|
|
|
|
|
val = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (c == '=') {
|
|
|
|
|
scan->accumulator_count = 0;
|
|
|
|
|
scan->accumulator = 0;
|
|
|
|
|
} else {
|
|
|
|
|
scan->accumulator = val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
base64_end (csi_t *ctx, csi_scanner_t *scan)
|
|
|
|
|
{
|
|
|
|
|
csi_object_t obj;
|
|
|
|
|
cairo_status_t status;
|
|
|
|
|
|
|
|
|
|
switch (scan->accumulator_count) {
|
|
|
|
|
case 0:
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
base64_add (ctx, scan, (scan->accumulator << 2) & 0x3f);
|
|
|
|
|
base64_add (ctx, scan, '=');
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
base64_add (ctx, scan, (scan->accumulator << 4) & 0x3f);
|
|
|
|
|
base64_add (ctx, scan, '=');
|
|
|
|
|
base64_add (ctx, scan, '=');
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = csi_string_new (ctx,
|
|
|
|
|
&obj,
|
|
|
|
|
scan->buffer.base,
|
|
|
|
|
scan->buffer.ptr - scan->buffer.base);
|
|
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2009-08-18 14:25:25 +01:00
|
|
|
|
|
|
|
|
if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
|
|
|
|
|
status = csi_array_append (ctx,
|
|
|
|
|
scan->build_procedure.datum.array,
|
|
|
|
|
&obj);
|
|
|
|
|
else
|
|
|
|
|
status = scan_push (ctx, &obj);
|
|
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2009-08-18 14:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2011-11-09 14:15:49 +01:00
|
|
|
static void
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_read (csi_scanner_t *scan, csi_file_t *src, void *ptr, int len)
|
|
|
|
|
{
|
|
|
|
|
uint8_t *data = ptr;
|
2009-07-23 22:00:05 +01:00
|
|
|
do {
|
2009-07-03 00:40:32 +01:00
|
|
|
int ret = csi_file_read (src, data, len);
|
|
|
|
|
if (_csi_unlikely (ret == 0))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_READ_ERROR));
|
2009-07-03 00:40:32 +01:00
|
|
|
data += ret;
|
|
|
|
|
len -= ret;
|
2009-07-23 22:00:05 +01:00
|
|
|
} while (_csi_unlikely (len));
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
static void
|
2009-08-10 16:45:41 +01:00
|
|
|
string_read (csi_t *ctx,
|
|
|
|
|
csi_scanner_t *scan,
|
|
|
|
|
csi_file_t *src,
|
|
|
|
|
int len,
|
|
|
|
|
int compressed,
|
|
|
|
|
csi_object_t *obj)
|
2008-11-13 11:07:45 +00:00
|
|
|
{
|
2009-07-03 00:40:32 +01:00
|
|
|
csi_status_t status;
|
|
|
|
|
|
2009-08-11 23:40:54 +01:00
|
|
|
status = csi_string_new (ctx, obj, NULL, len);
|
2009-07-03 00:40:32 +01:00
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2009-07-03 00:40:32 +01:00
|
|
|
|
2009-08-10 16:45:41 +01:00
|
|
|
if (compressed) {
|
|
|
|
|
uint32_t u32;
|
|
|
|
|
scan_read (scan, src, &u32, 4);
|
|
|
|
|
obj->datum.string->deflate = be32 (u32);
|
2013-01-04 17:32:46 +00:00
|
|
|
obj->datum.string->method = compressed;
|
2009-08-10 16:45:41 +01:00
|
|
|
}
|
|
|
|
|
|
2009-08-11 23:45:30 +01:00
|
|
|
if (_csi_likely (len))
|
|
|
|
|
scan_read (scan, src, obj->datum.string->string, len);
|
2009-08-06 23:41:11 +01:00
|
|
|
obj->datum.string->string[len] = '\0';
|
2009-07-03 00:40:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_scan_file (csi_t *ctx, csi_file_t *src)
|
|
|
|
|
{
|
|
|
|
|
csi_scanner_t *scan = &ctx->scanner;
|
2008-11-13 11:07:45 +00:00
|
|
|
int c, next;
|
|
|
|
|
union {
|
2009-07-03 00:40:32 +01:00
|
|
|
int8_t i8;
|
|
|
|
|
uint8_t u8;
|
|
|
|
|
int16_t i16;
|
|
|
|
|
uint16_t u16;
|
|
|
|
|
int32_t i32;
|
|
|
|
|
uint32_t u32;
|
2008-11-13 11:07:45 +00:00
|
|
|
float f;
|
|
|
|
|
} u;
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
int deflate = 0;
|
|
|
|
|
int string_p;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_none:
|
2009-06-28 00:48:05 +01:00
|
|
|
while ((c = csi_file_getc (src)) != EOF) {
|
2008-11-13 11:07:45 +00:00
|
|
|
csi_object_t obj = { CSI_OBJECT_TYPE_NULL };
|
|
|
|
|
|
|
|
|
|
switch (c) {
|
2009-06-19 14:13:34 +01:00
|
|
|
case 0xa:
|
|
|
|
|
scan->line_number++;
|
2008-11-13 11:07:45 +00:00
|
|
|
case 0x0:
|
|
|
|
|
case 0x9:
|
|
|
|
|
case 0xc:
|
|
|
|
|
case 0xd:
|
|
|
|
|
case 0x20: /* ignore whitespace */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '%':
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_comment;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
case '(':
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_string;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
case '[': /* needs special case */
|
|
|
|
|
case ']':
|
|
|
|
|
case '{':
|
|
|
|
|
case '}':
|
|
|
|
|
token_start (scan);
|
|
|
|
|
token_add_unchecked (scan, c);
|
|
|
|
|
token_end (ctx, scan, src);
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_none;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
case '<':
|
2009-06-28 00:48:05 +01:00
|
|
|
next = csi_file_getc (src);
|
2008-11-13 11:07:45 +00:00
|
|
|
switch (next) {
|
|
|
|
|
case EOF:
|
2009-06-28 00:48:05 +01:00
|
|
|
csi_file_putc (src, '<');
|
2009-07-03 00:40:32 +01:00
|
|
|
return;
|
2008-11-13 11:07:45 +00:00
|
|
|
case '<':
|
|
|
|
|
/* dictionary name */
|
|
|
|
|
token_start (scan);
|
|
|
|
|
token_add_unchecked (scan, '<');
|
|
|
|
|
token_add_unchecked (scan, '<');
|
|
|
|
|
token_end (ctx, scan, src);
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_none;
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
case '|':
|
|
|
|
|
deflate = 1;
|
2008-11-13 11:07:45 +00:00
|
|
|
case '~':
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_base85;
|
2009-08-18 14:25:25 +01:00
|
|
|
case '{':
|
|
|
|
|
goto scan_base64;
|
2008-11-13 11:07:45 +00:00
|
|
|
default:
|
2009-06-28 00:48:05 +01:00
|
|
|
csi_file_putc (src, next);
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_hex;
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* binary token */
|
2009-07-03 00:40:32 +01:00
|
|
|
#define MSB_INT8 128
|
|
|
|
|
#define MSB_UINT8 129
|
|
|
|
|
#define MSB_INT16 130
|
|
|
|
|
#define MSB_UINT16 131
|
|
|
|
|
#define MSB_INT32 132
|
|
|
|
|
#define LSB_INT8 MSB_INT8
|
|
|
|
|
#define LSB_UINT8 MSB_UINT8
|
|
|
|
|
#define LSB_INT16 133
|
|
|
|
|
#define LSB_UINT16 134
|
|
|
|
|
#define LSB_INT32 135
|
|
|
|
|
#define MSB_FLOAT32 140
|
|
|
|
|
#define LSB_FLOAT32 141
|
|
|
|
|
case MSB_INT8:
|
|
|
|
|
scan_read (scan, src, &u.i8, 1);
|
|
|
|
|
csi_integer_new (&obj, u.i8);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case MSB_UINT8:
|
|
|
|
|
scan_read (scan, src, &u.u8, 1);
|
|
|
|
|
csi_integer_new (&obj, u.u8);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case MSB_INT16:
|
|
|
|
|
scan_read (scan, src, &u.i16, 2);
|
|
|
|
|
csi_integer_new (&obj, be16 (u.i16));
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case LSB_INT16:
|
|
|
|
|
scan_read (scan, src, &u.i16, 2);
|
|
|
|
|
csi_integer_new (&obj, le16 (u.i16));
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case MSB_UINT16:
|
|
|
|
|
scan_read (scan, src, &u.u16, 2);
|
|
|
|
|
csi_integer_new (&obj, be16 (u.u16));
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case LSB_UINT16:
|
|
|
|
|
scan_read (scan, src, &u.u16, 2);
|
|
|
|
|
csi_integer_new (&obj, le16 (u.u16));
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case MSB_INT32:
|
|
|
|
|
scan_read (scan, src, &u.i32, 4);
|
|
|
|
|
csi_integer_new (&obj, be32 (u.i32));
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case LSB_INT32:
|
|
|
|
|
scan_read (scan, src, &u.i32, 4);
|
|
|
|
|
csi_integer_new (&obj, le32 (u.i32));
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
|
|
|
|
|
case 136: /* 16.16 msb */
|
|
|
|
|
scan_read (scan, src, &u.i32, 4);
|
|
|
|
|
csi_real_new (&obj, be32 (u.i32) / 65536.);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case 137: /* 16.16 lsb */
|
|
|
|
|
scan_read (scan, src, &u.i32, 4);
|
|
|
|
|
csi_real_new (&obj, le32 (u.i32) / 65536.);
|
|
|
|
|
break;
|
|
|
|
|
case 138: /* 24.8 msb */
|
|
|
|
|
scan_read (scan, src, &u.i32, 4);
|
|
|
|
|
csi_real_new (&obj, be32 (u.i32) / 256.);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case 139: /* 24.8 lsb */
|
|
|
|
|
scan_read (scan, src, &u.i32, 4);
|
|
|
|
|
csi_real_new (&obj, le32 (u.i32) / 256.);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case MSB_FLOAT32:
|
|
|
|
|
scan_read (scan, src, &u.i32, 4);
|
|
|
|
|
u.i32 = be32 (u.i32);
|
|
|
|
|
csi_real_new (&obj, u.f);
|
|
|
|
|
break;
|
|
|
|
|
case LSB_FLOAT32:
|
|
|
|
|
scan_read (scan, src, &u.i32, 4);
|
|
|
|
|
u.i32 = le32 (u.i32);
|
|
|
|
|
csi_real_new (&obj, u.f);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
|
|
|
|
|
#define STRING_1 142
|
2009-08-10 16:45:41 +01:00
|
|
|
#define STRING_2_MSB 144
|
|
|
|
|
#define STRING_2_LSB 146
|
|
|
|
|
#define STRING_4_MSB 148
|
|
|
|
|
#define STRING_4_LSB 150
|
|
|
|
|
#define STRING_DEFLATE 1
|
2009-07-03 00:40:32 +01:00
|
|
|
case STRING_1:
|
2009-08-10 16:45:41 +01:00
|
|
|
case STRING_1 | STRING_DEFLATE:
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_read (scan, src, &u.u8, 1);
|
2009-08-10 16:45:41 +01:00
|
|
|
string_read (ctx, scan, src, u.u8, c & STRING_DEFLATE, &obj);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case STRING_2_MSB:
|
2009-08-10 16:45:41 +01:00
|
|
|
case STRING_2_MSB | STRING_DEFLATE:
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_read (scan, src, &u.u16, 2);
|
2009-08-10 16:45:41 +01:00
|
|
|
string_read (ctx, scan, src, be16 (u.u16), c & STRING_DEFLATE, &obj);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case STRING_2_LSB:
|
2009-08-10 16:45:41 +01:00
|
|
|
case STRING_2_LSB | STRING_DEFLATE:
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_read (scan, src, &u.u16, 2);
|
2009-08-10 16:45:41 +01:00
|
|
|
string_read (ctx, scan, src, le16 (u.u16), c & STRING_DEFLATE, &obj);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case STRING_4_MSB:
|
2009-08-10 16:45:41 +01:00
|
|
|
case STRING_4_MSB | STRING_DEFLATE:
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_read (scan, src, &u.u32, 4);
|
2009-08-10 16:45:41 +01:00
|
|
|
string_read (ctx, scan, src, be32 (u.u32), c & STRING_DEFLATE, &obj);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
case STRING_4_LSB:
|
2009-08-10 16:45:41 +01:00
|
|
|
case STRING_4_LSB | STRING_DEFLATE:
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_read (scan, src, &u.u32, 4);
|
2009-08-10 16:45:41 +01:00
|
|
|
string_read (ctx, scan, src, le32 (u.u32), c & STRING_DEFLATE, &obj);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
|
2009-08-10 16:45:41 +01:00
|
|
|
#define OPCODE 152
|
|
|
|
|
case OPCODE:
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_read (scan, src, &u.u8, 1);
|
|
|
|
|
csi_operator_new (&obj, ctx->opcode[u.u8]);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
2009-07-03 00:40:32 +01:00
|
|
|
|
2009-08-10 16:45:41 +01:00
|
|
|
case OPCODE | 1:
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_read (scan, src, &u.u8, 1);
|
|
|
|
|
csi_operator_new (&obj, ctx->opcode[u.u8]);
|
|
|
|
|
obj.type &= ~CSI_OBJECT_ATTR_EXECUTABLE;
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
|
|
|
|
|
2013-01-04 17:32:46 +00:00
|
|
|
#define STRING_LZO 154
|
|
|
|
|
case STRING_LZO:
|
|
|
|
|
scan_read (scan, src, &u.u32, 4);
|
|
|
|
|
string_read (ctx, scan, src, be32 (u.u32), LZO, &obj);
|
|
|
|
|
break;
|
|
|
|
|
|
2008-11-13 11:07:45 +00:00
|
|
|
/* unassigned */
|
|
|
|
|
case 155:
|
|
|
|
|
case 156:
|
|
|
|
|
case 157:
|
|
|
|
|
case 158:
|
|
|
|
|
case 159:
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
case '#': /* PDF 1.2 escape code */
|
|
|
|
|
{
|
2009-06-28 00:48:05 +01:00
|
|
|
int c_hi = csi_file_getc (src);
|
|
|
|
|
int c_lo = csi_file_getc (src);
|
2008-11-13 11:07:45 +00:00
|
|
|
c = (hex_value (c_hi) << 4) | hex_value (c_lo);
|
|
|
|
|
}
|
|
|
|
|
/* fall-through */
|
|
|
|
|
default:
|
|
|
|
|
token_start (scan);
|
|
|
|
|
token_add_unchecked (scan, c);
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_token;
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (obj.type != CSI_OBJECT_TYPE_NULL) {
|
2009-06-28 00:48:05 +01:00
|
|
|
cairo_status_t status;
|
|
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) {
|
2009-06-28 00:48:05 +01:00
|
|
|
status = csi_array_append (ctx,
|
|
|
|
|
scan->build_procedure.datum.array,
|
|
|
|
|
&obj);
|
2009-07-03 00:40:32 +01:00
|
|
|
} else if (obj.type & CSI_OBJECT_ATTR_EXECUTABLE) {
|
|
|
|
|
status = scan_execute (ctx, &obj);
|
|
|
|
|
csi_object_free (ctx, &obj);
|
|
|
|
|
} else {
|
|
|
|
|
status = scan_push (ctx, &obj);
|
|
|
|
|
}
|
2009-06-28 00:48:05 +01:00
|
|
|
if (_csi_unlikely (status))
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, status);
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-07-03 00:40:32 +01:00
|
|
|
return;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_token:
|
2009-06-28 00:48:05 +01:00
|
|
|
while ((c = csi_file_getc (src)) != EOF) {
|
2008-11-13 11:07:45 +00:00
|
|
|
switch (c) {
|
2009-06-19 14:13:34 +01:00
|
|
|
case 0xa:
|
|
|
|
|
scan->line_number++;
|
2020-08-31 22:14:59 -06:00
|
|
|
/* fall through */
|
2008-11-13 11:07:45 +00:00
|
|
|
case 0x0:
|
|
|
|
|
case 0x9:
|
|
|
|
|
case 0xc:
|
|
|
|
|
case 0xd:
|
|
|
|
|
case 0x20:
|
|
|
|
|
token_end (ctx, scan, src);
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_none;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
/* syntax delimiters */
|
|
|
|
|
case '%':
|
|
|
|
|
token_end (ctx, scan, src);
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_comment;
|
2008-11-13 11:07:45 +00:00
|
|
|
/* syntax error? */
|
|
|
|
|
case '(':
|
|
|
|
|
token_end (ctx, scan, src);
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_string;
|
2008-11-13 11:07:45 +00:00
|
|
|
/* XXX syntax error? */
|
|
|
|
|
case ')':
|
|
|
|
|
token_end (ctx, scan, src);
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_none;
|
2008-11-13 11:07:45 +00:00
|
|
|
case '/':
|
|
|
|
|
/* need to special case '^//?' */
|
|
|
|
|
if (scan->buffer.ptr > scan->buffer.base+1 ||
|
|
|
|
|
scan->buffer.base[0] != '/')
|
|
|
|
|
{
|
|
|
|
|
token_end (ctx, scan, src);
|
|
|
|
|
token_start (scan);
|
|
|
|
|
}
|
|
|
|
|
token_add_unchecked (scan, '/');
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_token;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
case '{':
|
|
|
|
|
case '}':
|
|
|
|
|
case ']':
|
|
|
|
|
token_end (ctx, scan, src);
|
|
|
|
|
token_start (scan);
|
|
|
|
|
token_add_unchecked (scan, c);
|
|
|
|
|
token_end (ctx, scan, src);
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_none;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
case '<':
|
2009-06-28 00:48:05 +01:00
|
|
|
csi_file_putc (src, '<');
|
2008-11-13 11:07:45 +00:00
|
|
|
token_end (ctx, scan, src);
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_none;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
case '#': /* PDF 1.2 escape code */
|
|
|
|
|
{
|
2009-06-28 00:48:05 +01:00
|
|
|
int c_hi = csi_file_getc (src);
|
|
|
|
|
int c_lo = csi_file_getc (src);
|
2008-11-13 11:07:45 +00:00
|
|
|
c = (hex_value (c_hi) << 4) | hex_value (c_lo);
|
|
|
|
|
}
|
|
|
|
|
/* fall-through */
|
|
|
|
|
default:
|
|
|
|
|
token_add (ctx, scan, c);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
token_end (ctx, scan, src);
|
2009-07-03 00:40:32 +01:00
|
|
|
return;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_comment:
|
|
|
|
|
/* discard until newline */
|
2009-06-28 00:48:05 +01:00
|
|
|
while ((c = csi_file_getc (src)) != EOF) {
|
2008-11-13 11:07:45 +00:00
|
|
|
switch (c) {
|
2009-06-19 14:13:34 +01:00
|
|
|
case 0xa:
|
|
|
|
|
scan->line_number++;
|
2008-11-13 11:07:45 +00:00
|
|
|
case 0xc:
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_none;
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-07-03 00:40:32 +01:00
|
|
|
return;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_string:
|
|
|
|
|
buffer_reset (&scan->buffer);
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
string_p = 1;
|
2009-06-28 00:48:05 +01:00
|
|
|
while ((c = csi_file_getc (src)) != EOF) {
|
2008-11-13 11:07:45 +00:00
|
|
|
switch (c) {
|
|
|
|
|
case '\\': /* escape */
|
2009-06-28 00:48:05 +01:00
|
|
|
next = csi_file_getc (src);
|
2008-11-13 11:07:45 +00:00
|
|
|
switch (next) {
|
|
|
|
|
case EOF:
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
case 'n':
|
|
|
|
|
string_add (ctx, scan, '\n');
|
|
|
|
|
break;
|
|
|
|
|
case 'r':
|
|
|
|
|
string_add (ctx, scan, '\r');
|
|
|
|
|
break;
|
|
|
|
|
case 't':
|
2008-12-09 05:59:19 +02:00
|
|
|
string_add (ctx, scan, '\t');
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
|
|
|
|
case 'b':
|
|
|
|
|
string_add (ctx, scan, '\b');
|
|
|
|
|
break;
|
|
|
|
|
case 'f':
|
|
|
|
|
string_add (ctx, scan, '\f');
|
|
|
|
|
break;
|
|
|
|
|
case '\\':
|
|
|
|
|
string_add (ctx, scan, '\\');
|
|
|
|
|
break;
|
|
|
|
|
case '(':
|
|
|
|
|
string_add (ctx, scan, '(');
|
|
|
|
|
break;
|
|
|
|
|
case ')':
|
|
|
|
|
string_add (ctx, scan, ')');
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '0': case '1': case '2': case '3':
|
|
|
|
|
case '4': case '5': case '6': case '7':
|
|
|
|
|
{ /* octal code: \d{1,3} */
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
c = next - '0';
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 2; i++) {
|
2009-06-28 00:48:05 +01:00
|
|
|
next = csi_file_getc (src);
|
2008-11-13 11:07:45 +00:00
|
|
|
switch (next) {
|
|
|
|
|
case EOF:
|
2009-07-03 00:40:32 +01:00
|
|
|
return;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
|
|
|
|
case '0': case '1': case '2': case '3':
|
|
|
|
|
case '4': case '5': case '6': case '7':
|
|
|
|
|
c = 8*c + next-'0';
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2009-06-28 00:48:05 +01:00
|
|
|
csi_file_putc (src, next);
|
2008-11-13 11:07:45 +00:00
|
|
|
goto octal_code_done;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
octal_code_done:
|
|
|
|
|
string_add (ctx, scan, c);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0xa:
|
|
|
|
|
/* skip the newline */
|
2009-06-28 00:48:05 +01:00
|
|
|
next = csi_file_getc (src); /* might be compound LFCR */
|
2008-11-13 11:07:45 +00:00
|
|
|
switch (next) {
|
|
|
|
|
case EOF:
|
2009-07-03 00:40:32 +01:00
|
|
|
return;
|
2008-11-13 11:07:45 +00:00
|
|
|
case 0xc:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2009-06-28 00:48:05 +01:00
|
|
|
csi_file_putc (src, next);
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2009-06-19 14:13:34 +01:00
|
|
|
scan->line_number++;
|
2008-11-13 11:07:45 +00:00
|
|
|
break;
|
|
|
|
|
case 0xc:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* ignore the '\' */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '(':
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
string_p++;
|
2008-11-13 11:07:45 +00:00
|
|
|
string_add (ctx, scan, c);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ')':
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
if (--string_p == 0) {
|
2008-11-13 11:07:45 +00:00
|
|
|
string_end (ctx, scan);
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_none;
|
|
|
|
|
}
|
|
|
|
|
/* fall through */
|
2008-11-13 11:07:45 +00:00
|
|
|
default:
|
|
|
|
|
string_add (ctx, scan, c);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_hex:
|
|
|
|
|
buffer_reset (&scan->buffer);
|
|
|
|
|
scan->accumulator_count = 0;
|
|
|
|
|
scan->accumulator = 0;
|
2009-06-28 00:48:05 +01:00
|
|
|
while ((c = csi_file_getc (src)) != EOF) {
|
2008-11-13 11:07:45 +00:00
|
|
|
switch (c) {
|
|
|
|
|
case 0xa:
|
2009-06-19 14:13:34 +01:00
|
|
|
scan->line_number++;
|
2009-07-03 00:40:32 +01:00
|
|
|
case 0x0:
|
|
|
|
|
case 0x9:
|
2008-11-13 11:07:45 +00:00
|
|
|
case 0xc:
|
2009-07-03 00:40:32 +01:00
|
|
|
case 0xd:
|
|
|
|
|
case 0x20: /* ignore whitespace */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '>':
|
|
|
|
|
hex_end (ctx, scan); /* fixup odd digit with '0' */
|
|
|
|
|
goto scan_none;
|
|
|
|
|
|
|
|
|
|
case '0':
|
|
|
|
|
case '1':
|
|
|
|
|
case '2':
|
|
|
|
|
case '3':
|
|
|
|
|
case '4':
|
|
|
|
|
case '5':
|
|
|
|
|
case '6':
|
|
|
|
|
case '7':
|
|
|
|
|
case '8':
|
|
|
|
|
case '9':
|
|
|
|
|
case 'a':
|
|
|
|
|
case 'b':
|
|
|
|
|
case 'c':
|
|
|
|
|
case 'd':
|
|
|
|
|
case 'e':
|
|
|
|
|
case 'f':
|
|
|
|
|
case 'A':
|
|
|
|
|
case 'B':
|
|
|
|
|
case 'C':
|
|
|
|
|
case 'D':
|
|
|
|
|
case 'E':
|
|
|
|
|
case 'F':
|
|
|
|
|
hex_add (ctx, scan, c);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
}
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
scan_base85:
|
|
|
|
|
buffer_reset (&scan->buffer);
|
|
|
|
|
scan->accumulator = 0;
|
|
|
|
|
scan->accumulator_count = 0;
|
|
|
|
|
while ((c = csi_file_getc (src)) != EOF) {
|
|
|
|
|
switch (c) {
|
|
|
|
|
case '~':
|
|
|
|
|
next = csi_file_getc (src);
|
|
|
|
|
switch (next) {
|
|
|
|
|
case EOF:
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case '>':
|
Remove clip handling from generic surface layer.
Handling clip as part of the surface state, as opposed to being part of
the operation state, is cumbersome and a hindrance to providing true proxy
surface support. For example, the clip must be copied from the surface
onto the fallback image, but this was forgotten causing undue hassle in
each backend. Another example is the contortion the meta surface
endures to ensure the clip is correctly recorded. By contrast passing the
clip along with the operation is quite simple and enables us to write
generic handlers for providing surface wrappers. (And in the future, we
should be able to write more esoteric wrappers, e.g. automatic 2x FSAA,
trivially.)
In brief, instead of the surface automatically applying the clip before
calling the backend, the backend can call into a generic helper to apply
clipping. For raster surfaces, clip regions are handled automatically as
part of the composite interface. For vector surfaces, a clip helper is
introduced to replay and callback into an intersect_clip_path() function
as necessary.
Whilst this is not primarily a performance related change (the change
should just move the computation of the clip from the moment it is applied
by the user to the moment it is required by the backend), it is important
to track any potential regression:
ppc:
Speedups
========
image-rgba evolution-20090607-0 1026085.22 0.18% -> 672972.07 0.77%: 1.52x speedup
▌
image-rgba evolution-20090618-0 680579.98 0.12% -> 573237.66 0.16%: 1.19x speedup
▎
image-rgba swfdec-fill-rate-4xaa-0 460296.92 0.36% -> 407464.63 0.42%: 1.13x speedup
▏
image-rgba swfdec-fill-rate-2xaa-0 128431.95 0.47% -> 115051.86 0.42%: 1.12x speedup
▏
Slowdowns
=========
image-rgba firefox-periodic-table-0 56837.61 0.78% -> 66055.17 3.20%: 1.09x slowdown
▏
2009-07-23 15:32:13 +01:00
|
|
|
base85_end (ctx, scan, deflate);
|
|
|
|
|
deflate = 0;
|
2009-07-03 00:40:32 +01:00
|
|
|
goto scan_none;
|
|
|
|
|
}
|
|
|
|
|
csi_file_putc (src, next);
|
|
|
|
|
|
|
|
|
|
/* fall-through */
|
|
|
|
|
default:
|
|
|
|
|
base85_add (ctx, scan, c);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2009-08-18 14:25:25 +01:00
|
|
|
|
|
|
|
|
scan_base64:
|
|
|
|
|
buffer_reset (&scan->buffer);
|
|
|
|
|
scan->accumulator = 0;
|
|
|
|
|
scan->accumulator_count = 0;
|
|
|
|
|
while ((c = csi_file_getc (src)) != EOF) {
|
|
|
|
|
switch (c) {
|
|
|
|
|
case '}':
|
|
|
|
|
next = csi_file_getc (src);
|
|
|
|
|
switch (next) {
|
|
|
|
|
case EOF:
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case '>':
|
|
|
|
|
base64_end (ctx, scan);
|
|
|
|
|
goto scan_none;
|
|
|
|
|
}
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2009-08-18 14:25:25 +01:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
base64_add (ctx, scan, c);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2009-07-03 00:40:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static csi_status_t
|
|
|
|
|
_scan_push (csi_t *ctx, csi_object_t *obj)
|
|
|
|
|
{
|
2009-07-04 18:32:57 +01:00
|
|
|
if (DEBUG_SCAN) {
|
2009-07-03 00:40:32 +01:00
|
|
|
fprintf (stderr, "push ");
|
|
|
|
|
fprintf_obj (stderr, ctx, obj);
|
|
|
|
|
}
|
|
|
|
|
return _csi_push_ostack (ctx, obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static csi_status_t
|
|
|
|
|
_scan_execute (csi_t *ctx, csi_object_t *obj)
|
|
|
|
|
{
|
2009-07-04 18:32:57 +01:00
|
|
|
if (DEBUG_SCAN) {
|
2009-07-03 00:40:32 +01:00
|
|
|
fprintf (stderr, "exec ");
|
|
|
|
|
fprintf_obj (stderr, ctx, obj);
|
|
|
|
|
}
|
|
|
|
|
return csi_object_execute (ctx, obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
csi_status_t
|
|
|
|
|
_csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner)
|
|
|
|
|
{
|
|
|
|
|
csi_status_t status;
|
|
|
|
|
|
|
|
|
|
memset (scanner, 0, sizeof (csi_scanner_t));
|
|
|
|
|
|
|
|
|
|
status = buffer_init (ctx, &scanner->buffer);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
status = _csi_stack_init (ctx, &scanner->procedure_stack, 4);
|
|
|
|
|
if (status)
|
|
|
|
|
return status;
|
|
|
|
|
|
2009-08-11 21:26:11 +01:00
|
|
|
scanner->bind = 0;
|
2009-07-03 00:40:32 +01:00
|
|
|
scanner->push = _scan_push;
|
|
|
|
|
scanner->execute = _scan_execute;
|
|
|
|
|
|
|
|
|
|
return CSI_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
_csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner)
|
|
|
|
|
{
|
|
|
|
|
buffer_fini (ctx, &scanner->buffer);
|
|
|
|
|
_csi_stack_fini (ctx, &scanner->procedure_stack);
|
|
|
|
|
if (scanner->build_procedure.type != CSI_OBJECT_TYPE_NULL)
|
|
|
|
|
csi_object_free (ctx, &scanner->build_procedure);
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
csi_status_t
|
2009-07-03 00:40:32 +01:00
|
|
|
_csi_scan_file (csi_t *ctx, csi_file_t *src)
|
2008-11-13 11:07:45 +00:00
|
|
|
{
|
2009-06-28 00:48:05 +01:00
|
|
|
csi_status_t status;
|
2010-03-21 20:42:34 +00:00
|
|
|
int old_line_number;
|
2009-06-28 00:48:05 +01:00
|
|
|
|
2009-06-28 20:41:04 +01:00
|
|
|
/* This function needs to be reentrant to handle recursive scanners.
|
|
|
|
|
* i.e. one script executes a second.
|
|
|
|
|
*/
|
|
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
if (ctx->scanner.depth++ == 0) {
|
2015-06-16 16:42:56 -07:00
|
|
|
if ((status = setjmp (ctx->scanner.jump_buffer))) {
|
2009-07-03 00:40:32 +01:00
|
|
|
ctx->scanner.depth = 0;
|
2009-06-28 20:41:04 +01:00
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2010-03-21 20:42:34 +00:00
|
|
|
old_line_number = ctx->scanner.line_number;
|
|
|
|
|
ctx->scanner.line_number = 0;
|
|
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
_scan_file (ctx, src);
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2010-03-21 20:42:34 +00:00
|
|
|
ctx->scanner.line_number = old_line_number;
|
|
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
--ctx->scanner.depth;
|
2009-06-28 00:48:05 +01:00
|
|
|
return CSI_STATUS_SUCCESS;
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
struct _translate_closure {
|
|
|
|
|
csi_dictionary_t *opcodes;
|
|
|
|
|
cairo_write_func_t write_func;
|
|
|
|
|
void *closure;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static csi_status_t
|
|
|
|
|
_translate_name (csi_t *ctx,
|
|
|
|
|
csi_name_t name,
|
|
|
|
|
csi_boolean_t executable,
|
|
|
|
|
struct _translate_closure *closure)
|
2008-11-13 11:07:45 +00:00
|
|
|
{
|
2009-07-03 00:40:32 +01:00
|
|
|
if (executable) {
|
|
|
|
|
csi_dictionary_entry_t *entry;
|
|
|
|
|
uint16_t u16;
|
|
|
|
|
|
|
|
|
|
/* Bind executable names.
|
|
|
|
|
* XXX This may break some scripts that overload system operators.
|
|
|
|
|
*/
|
|
|
|
|
entry = _csi_hash_table_lookup (&closure->opcodes->hash_table,
|
|
|
|
|
(csi_hash_entry_t *) &name);
|
|
|
|
|
if (entry == NULL)
|
|
|
|
|
goto STRING;
|
|
|
|
|
|
|
|
|
|
u16 = entry->value.datum.integer;
|
|
|
|
|
u16 = be16 (u16);
|
|
|
|
|
closure->write_func (closure->closure, (unsigned char *) &u16, 2);
|
|
|
|
|
} else {
|
|
|
|
|
closure->write_func (closure->closure, (unsigned char *) "/", 1);
|
|
|
|
|
STRING:
|
|
|
|
|
closure->write_func (closure->closure,
|
|
|
|
|
(unsigned char *) name,
|
|
|
|
|
strlen ((char *) name));
|
|
|
|
|
closure->write_func (closure->closure, (unsigned char *) "\n", 1);
|
|
|
|
|
}
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
return CSI_STATUS_SUCCESS;
|
|
|
|
|
}
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
static csi_status_t
|
|
|
|
|
_translate_operator (csi_t *ctx,
|
|
|
|
|
csi_operator_t op,
|
|
|
|
|
csi_boolean_t executable,
|
|
|
|
|
struct _translate_closure *closure)
|
|
|
|
|
{
|
|
|
|
|
csi_dictionary_entry_t *entry;
|
|
|
|
|
uint16_t u16;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
entry = _csi_hash_table_lookup (&closure->opcodes->hash_table,
|
|
|
|
|
(csi_hash_entry_t *) &op);
|
|
|
|
|
if (entry == NULL)
|
|
|
|
|
return _csi_error (CSI_STATUS_INVALID_SCRIPT);
|
|
|
|
|
|
|
|
|
|
u16 = entry->value.datum.integer;
|
|
|
|
|
if (! executable)
|
|
|
|
|
u16 += 1 << 8;
|
|
|
|
|
u16 = be16 (u16);
|
|
|
|
|
closure->write_func (closure->closure, (unsigned char *) &u16, 2);
|
|
|
|
|
|
|
|
|
|
return CSI_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static csi_status_t
|
|
|
|
|
_translate_integer (csi_t *ctx,
|
|
|
|
|
csi_integer_t i,
|
|
|
|
|
struct _translate_closure *closure)
|
|
|
|
|
{
|
|
|
|
|
uint8_t hdr;
|
|
|
|
|
union {
|
|
|
|
|
int8_t i8;
|
|
|
|
|
uint8_t u8;
|
|
|
|
|
int16_t i16;
|
|
|
|
|
uint16_t u16;
|
|
|
|
|
int32_t i32;
|
|
|
|
|
uint32_t u32;
|
|
|
|
|
} u;
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
#if WORDS_BIGENDIAN
|
|
|
|
|
if (i < INT16_MIN) {
|
|
|
|
|
hdr = MSB_INT32;
|
|
|
|
|
len = 4;
|
|
|
|
|
u.i32 = i;
|
|
|
|
|
} else if (i < INT8_MIN) {
|
|
|
|
|
hdr = MSB_INT16;
|
|
|
|
|
len = 2;
|
|
|
|
|
u.i16 = i;
|
|
|
|
|
} else if (i < 0) {
|
|
|
|
|
hdr = MSB_INT8;
|
|
|
|
|
len = 1;
|
|
|
|
|
u.i8 = i;
|
|
|
|
|
} else if (i <= UINT8_MAX) {
|
|
|
|
|
hdr = MSB_UINT8;
|
|
|
|
|
len = 1;
|
|
|
|
|
u.u8 = i;
|
|
|
|
|
} else if (i <= UINT16_MAX) {
|
|
|
|
|
hdr = MSB_UINT16;
|
|
|
|
|
len = 2;
|
|
|
|
|
u.u16 = i;
|
|
|
|
|
} else {
|
|
|
|
|
hdr = MSB_INT32;
|
|
|
|
|
len = 4;
|
|
|
|
|
u.u32 = i;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
if (i < INT16_MIN) {
|
|
|
|
|
hdr = LSB_INT32;
|
|
|
|
|
len = 4;
|
|
|
|
|
u.i32 = i;
|
|
|
|
|
} else if (i < INT8_MIN) {
|
|
|
|
|
hdr = LSB_INT16;
|
|
|
|
|
len = 2;
|
|
|
|
|
u.i16 = i;
|
|
|
|
|
} else if (i < 0) {
|
|
|
|
|
hdr = LSB_INT8;
|
|
|
|
|
len = 1;
|
|
|
|
|
u.i8 = i;
|
|
|
|
|
} else if (i <= UINT8_MAX) {
|
|
|
|
|
hdr = LSB_UINT8;
|
|
|
|
|
len = 1;
|
|
|
|
|
u.u8 = i;
|
|
|
|
|
} else if (i <= UINT16_MAX) {
|
|
|
|
|
hdr = LSB_UINT16;
|
|
|
|
|
len = 2;
|
|
|
|
|
u.u16 = i;
|
|
|
|
|
} else {
|
|
|
|
|
hdr = LSB_INT32;
|
|
|
|
|
len = 4;
|
|
|
|
|
u.u32 = i;
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
2009-07-03 00:40:32 +01:00
|
|
|
#endif
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
closure->write_func (closure->closure, (unsigned char *) &hdr, 1);
|
|
|
|
|
closure->write_func (closure->closure, (unsigned char *) &u, len);
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
return CSI_STATUS_SUCCESS;
|
|
|
|
|
}
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
static csi_status_t
|
|
|
|
|
_translate_real (csi_t *ctx,
|
|
|
|
|
csi_real_t real,
|
|
|
|
|
struct _translate_closure *closure)
|
|
|
|
|
{
|
|
|
|
|
uint8_t hdr;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2024-02-17 20:36:53 +10:30
|
|
|
if ((double)real >= INT32_MIN && (double)real <= INT32_MAX && (int) real == real)
|
2009-07-03 00:40:32 +01:00
|
|
|
return _translate_integer (ctx, real, closure);
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
#if WORDS_BIGENDIAN
|
|
|
|
|
hdr = MSB_FLOAT32;
|
|
|
|
|
#else
|
|
|
|
|
hdr = LSB_FLOAT32;
|
|
|
|
|
#endif
|
|
|
|
|
closure->write_func (closure->closure, (unsigned char *) &hdr, 1);
|
|
|
|
|
closure->write_func (closure->closure, (unsigned char *) &real, 4);
|
|
|
|
|
|
|
|
|
|
return CSI_STATUS_SUCCESS;
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
2009-07-03 00:40:32 +01:00
|
|
|
|
|
|
|
|
static csi_status_t
|
|
|
|
|
_translate_string (csi_t *ctx,
|
|
|
|
|
csi_string_t *string,
|
|
|
|
|
struct _translate_closure *closure)
|
|
|
|
|
{
|
|
|
|
|
uint8_t hdr;
|
|
|
|
|
union {
|
|
|
|
|
uint8_t u8;
|
|
|
|
|
uint16_t u16;
|
|
|
|
|
uint32_t u32;
|
|
|
|
|
} u;
|
2013-01-04 17:32:46 +00:00
|
|
|
void *buf;
|
|
|
|
|
unsigned long hdr_len, buf_len, deflate;
|
|
|
|
|
int method;
|
|
|
|
|
|
|
|
|
|
buf = string->string;
|
|
|
|
|
buf_len = string->len;
|
|
|
|
|
deflate = string->deflate;
|
|
|
|
|
method = string->method;
|
|
|
|
|
|
|
|
|
|
#if HAVE_LZO
|
|
|
|
|
if (method == NONE && buf_len > 16) {
|
|
|
|
|
unsigned long mem_len = 2*string->len > LZO2A_999_MEM_COMPRESS ? 2*string->len : LZO2A_999_MEM_COMPRESS;
|
|
|
|
|
void *mem = malloc (mem_len);
|
|
|
|
|
void *work = malloc(LZO2A_999_MEM_COMPRESS);
|
|
|
|
|
|
|
|
|
|
if (lzo2a_999_compress ((lzo_bytep) buf, buf_len,
|
|
|
|
|
(lzo_bytep) mem, &mem_len,
|
|
|
|
|
work) == 0 &&
|
|
|
|
|
8+2*mem_len < buf_len)
|
|
|
|
|
{
|
|
|
|
|
method = LZO;
|
|
|
|
|
deflate = buf_len;
|
|
|
|
|
buf_len = mem_len;
|
|
|
|
|
buf = mem;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
free (mem);
|
|
|
|
|
}
|
2009-07-03 00:40:32 +01:00
|
|
|
|
2013-01-04 17:32:46 +00:00
|
|
|
free (work);
|
2009-07-03 00:40:32 +01:00
|
|
|
}
|
2013-01-04 17:32:46 +00:00
|
|
|
#if HAVE_ZLIB
|
|
|
|
|
if (method == ZLIB) {
|
|
|
|
|
buf_len = string->deflate;
|
|
|
|
|
buf = malloc (string->deflate);
|
|
|
|
|
if (uncompress ((Bytef *) buf, &buf_len,
|
|
|
|
|
(Bytef *) string->string, string->len) == Z_OK)
|
|
|
|
|
{
|
2015-06-04 14:24:31 -07:00
|
|
|
assert(string->len > 0);
|
|
|
|
|
if (buf_len <= 8 + 2*((unsigned long)string->len)) {
|
2013-01-04 17:32:46 +00:00
|
|
|
method = NONE;
|
|
|
|
|
deflate = 0;
|
|
|
|
|
} else {
|
|
|
|
|
unsigned long mem_len = 2*string->deflate;
|
|
|
|
|
void *mem = malloc (mem_len);
|
|
|
|
|
void *work = malloc(LZO2A_999_MEM_COMPRESS);
|
|
|
|
|
|
|
|
|
|
if (lzo2a_999_compress ((lzo_bytep) buf, buf_len,
|
|
|
|
|
(lzo_bytep) mem, &mem_len,
|
|
|
|
|
work) == 0)
|
|
|
|
|
{
|
|
|
|
|
if (8 + mem_len > buf_len) {
|
|
|
|
|
method = NONE;
|
|
|
|
|
deflate = 0;
|
|
|
|
|
} else {
|
|
|
|
|
free (buf);
|
|
|
|
|
method = LZO;
|
|
|
|
|
deflate = buf_len;
|
|
|
|
|
buf_len = mem_len;
|
|
|
|
|
buf = mem;
|
|
|
|
|
assert(deflate);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
free (buf);
|
|
|
|
|
buf = string->string;
|
|
|
|
|
buf_len = string->len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free (work);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
free (buf);
|
|
|
|
|
buf = string->string;
|
|
|
|
|
buf_len = string->len;
|
|
|
|
|
}
|
2009-07-03 00:40:32 +01:00
|
|
|
}
|
2008-11-13 11:07:45 +00:00
|
|
|
#endif
|
2013-01-04 17:32:46 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (method == LZO) {
|
|
|
|
|
hdr = STRING_LZO;
|
|
|
|
|
u.u32 = to_be32 (buf_len);
|
|
|
|
|
hdr_len = 4;
|
|
|
|
|
} else {
|
|
|
|
|
#if WORDS_BIGENDIAN
|
|
|
|
|
if (buf_len <= UINT8_MAX) {
|
|
|
|
|
hdr = STRING_1;
|
|
|
|
|
u.u8 = buf_len;
|
|
|
|
|
hdr_len = 1;
|
|
|
|
|
} else if (buf_len <= UINT16_MAX) {
|
|
|
|
|
hdr = STRING_2_MSB;
|
|
|
|
|
u.u16 = buf_len;
|
|
|
|
|
hdr_len = 2;
|
|
|
|
|
} else {
|
|
|
|
|
hdr = STRING_4_MSB;
|
|
|
|
|
u.u32 = buf_len;
|
|
|
|
|
hdr_len = 4;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
if (buf_len <= UINT8_MAX) {
|
|
|
|
|
hdr = STRING_1;
|
|
|
|
|
u.u8 = buf_len;
|
|
|
|
|
hdr_len = 1;
|
|
|
|
|
} else if (buf_len <= UINT16_MAX) {
|
|
|
|
|
hdr = STRING_2_LSB;
|
|
|
|
|
u.u16 = buf_len;
|
|
|
|
|
hdr_len = 2;
|
|
|
|
|
} else {
|
|
|
|
|
hdr = STRING_4_LSB;
|
|
|
|
|
u.u32 = buf_len;
|
|
|
|
|
hdr_len = 4;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if (deflate) {
|
|
|
|
|
assert (method == ZLIB);
|
|
|
|
|
hdr |= STRING_DEFLATE;
|
|
|
|
|
}
|
2009-08-10 16:45:41 +01:00
|
|
|
}
|
2013-01-04 17:32:46 +00:00
|
|
|
|
|
|
|
|
closure->write_func (closure->closure, (unsigned char *) &hdr, 1);
|
|
|
|
|
closure->write_func (closure->closure, (unsigned char *) &u, hdr_len);
|
|
|
|
|
if (deflate) {
|
|
|
|
|
uint32_t u32 = to_be32 (deflate);
|
|
|
|
|
closure->write_func (closure->closure, (unsigned char *) &u32, 4);
|
|
|
|
|
}
|
|
|
|
|
closure->write_func (closure->closure, (unsigned char *) buf, buf_len);
|
|
|
|
|
|
|
|
|
|
if (buf != string->string)
|
|
|
|
|
free (buf);
|
2009-07-03 00:40:32 +01:00
|
|
|
|
|
|
|
|
return CSI_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static csi_status_t
|
|
|
|
|
_translate_push (csi_t *ctx, csi_object_t *obj)
|
2008-11-13 11:07:45 +00:00
|
|
|
{
|
2009-07-03 00:40:32 +01:00
|
|
|
struct _translate_closure *closure = ctx->scanner.closure;
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
if (0) {
|
|
|
|
|
fprintf (stderr, "push ");
|
|
|
|
|
fprintf_obj (stderr, ctx, obj);
|
|
|
|
|
}
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
switch (csi_object_get_type (obj)) {
|
|
|
|
|
case CSI_OBJECT_TYPE_NAME:
|
|
|
|
|
return _translate_name (ctx, obj->datum.name, FALSE, closure);
|
|
|
|
|
|
|
|
|
|
case CSI_OBJECT_TYPE_OPERATOR:
|
|
|
|
|
return _translate_operator (ctx, obj->datum.op, FALSE, closure);
|
|
|
|
|
|
|
|
|
|
case CSI_OBJECT_TYPE_INTEGER:
|
|
|
|
|
return _translate_integer (ctx, obj->datum.integer, closure);
|
|
|
|
|
|
|
|
|
|
case CSI_OBJECT_TYPE_REAL:
|
|
|
|
|
return _translate_real (ctx, obj->datum.real, closure);
|
|
|
|
|
|
|
|
|
|
case CSI_OBJECT_TYPE_STRING:
|
|
|
|
|
return _translate_string (ctx, obj->datum.string, closure);
|
|
|
|
|
|
|
|
|
|
case CSI_OBJECT_TYPE_NULL:
|
|
|
|
|
case CSI_OBJECT_TYPE_BOOLEAN:
|
|
|
|
|
case CSI_OBJECT_TYPE_MARK:
|
|
|
|
|
case CSI_OBJECT_TYPE_ARRAY:
|
|
|
|
|
case CSI_OBJECT_TYPE_DICTIONARY:
|
|
|
|
|
case CSI_OBJECT_TYPE_FILE:
|
|
|
|
|
case CSI_OBJECT_TYPE_MATRIX:
|
|
|
|
|
case CSI_OBJECT_TYPE_CONTEXT:
|
|
|
|
|
case CSI_OBJECT_TYPE_FONT:
|
|
|
|
|
case CSI_OBJECT_TYPE_PATTERN:
|
|
|
|
|
case CSI_OBJECT_TYPE_SCALED_FONT:
|
|
|
|
|
case CSI_OBJECT_TYPE_SURFACE:
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (ctx->scanner.jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2009-07-03 00:40:32 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
csi_object_free (ctx, obj);
|
|
|
|
|
return CSI_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static csi_status_t
|
|
|
|
|
_translate_execute (csi_t *ctx, csi_object_t *obj)
|
|
|
|
|
{
|
|
|
|
|
struct _translate_closure *closure = ctx->scanner.closure;
|
|
|
|
|
|
|
|
|
|
if (0) {
|
|
|
|
|
fprintf (stderr, "exec ");
|
|
|
|
|
fprintf_obj (stderr, ctx, obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (csi_object_get_type (obj)) {
|
|
|
|
|
case CSI_OBJECT_TYPE_NAME:
|
|
|
|
|
return _translate_name (ctx, obj->datum.name, TRUE, closure);
|
|
|
|
|
|
|
|
|
|
case CSI_OBJECT_TYPE_OPERATOR:
|
|
|
|
|
return _translate_operator (ctx, obj->datum.op, TRUE, closure);
|
|
|
|
|
|
|
|
|
|
case CSI_OBJECT_TYPE_INTEGER:
|
|
|
|
|
return _translate_integer (ctx, obj->datum.integer, closure);
|
|
|
|
|
|
|
|
|
|
case CSI_OBJECT_TYPE_REAL:
|
|
|
|
|
return _translate_real (ctx, obj->datum.real, closure);
|
|
|
|
|
|
|
|
|
|
case CSI_OBJECT_TYPE_STRING:
|
|
|
|
|
return _translate_string (ctx, obj->datum.string, closure);
|
|
|
|
|
|
|
|
|
|
case CSI_OBJECT_TYPE_NULL:
|
|
|
|
|
case CSI_OBJECT_TYPE_BOOLEAN:
|
|
|
|
|
case CSI_OBJECT_TYPE_MARK:
|
|
|
|
|
case CSI_OBJECT_TYPE_ARRAY:
|
|
|
|
|
case CSI_OBJECT_TYPE_DICTIONARY:
|
|
|
|
|
case CSI_OBJECT_TYPE_FILE:
|
|
|
|
|
case CSI_OBJECT_TYPE_MATRIX:
|
|
|
|
|
case CSI_OBJECT_TYPE_CONTEXT:
|
|
|
|
|
case CSI_OBJECT_TYPE_FONT:
|
|
|
|
|
case CSI_OBJECT_TYPE_PATTERN:
|
|
|
|
|
case CSI_OBJECT_TYPE_SCALED_FONT:
|
|
|
|
|
case CSI_OBJECT_TYPE_SURFACE:
|
2015-06-16 16:42:56 -07:00
|
|
|
longjmp (ctx->scanner.jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
|
2009-07-03 00:40:32 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CSI_STATUS_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static csi_status_t
|
|
|
|
|
build_opcodes (csi_t *ctx, csi_dictionary_t **out)
|
|
|
|
|
{
|
|
|
|
|
csi_object_t obj;
|
|
|
|
|
csi_dictionary_t *dict;
|
|
|
|
|
const csi_operator_def_t *def;
|
|
|
|
|
csi_status_t status;
|
2009-08-10 16:45:41 +01:00
|
|
|
int opcode = OPCODE << 8;
|
2009-07-03 00:40:32 +01:00
|
|
|
|
|
|
|
|
status = csi_dictionary_new (ctx, &obj);
|
|
|
|
|
if (_csi_unlikely (status))
|
2008-11-13 11:07:45 +00:00
|
|
|
return status;
|
|
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
dict = obj.datum.dictionary;
|
|
|
|
|
|
|
|
|
|
csi_integer_new (&obj, opcode++);
|
|
|
|
|
status = csi_dictionary_put (ctx, dict, 0, &obj);
|
|
|
|
|
if (_csi_unlikely (status))
|
|
|
|
|
goto FAIL;
|
|
|
|
|
|
|
|
|
|
for (def = _csi_operators (); def->name != NULL; def++) {
|
|
|
|
|
csi_object_t name;
|
|
|
|
|
csi_dictionary_entry_t *entry;
|
|
|
|
|
int code;
|
|
|
|
|
|
|
|
|
|
entry = _csi_hash_table_lookup (&dict->hash_table,
|
|
|
|
|
(csi_hash_entry_t *) &def->op);
|
|
|
|
|
if (entry == NULL) {
|
|
|
|
|
code = opcode++;
|
|
|
|
|
csi_integer_new (&obj, code);
|
|
|
|
|
status = csi_dictionary_put (ctx, dict, (csi_name_t) def->op, &obj);
|
|
|
|
|
if (_csi_unlikely (status))
|
|
|
|
|
goto FAIL;
|
|
|
|
|
} else {
|
|
|
|
|
code = entry->value.datum.integer;
|
|
|
|
|
csi_integer_new (&obj, code);
|
|
|
|
|
}
|
|
|
|
|
assert (ctx->opcode[code & 0xff] == def->op);
|
|
|
|
|
|
|
|
|
|
status = csi_name_new_static (ctx, &name, def->name);
|
|
|
|
|
if (_csi_unlikely (status))
|
|
|
|
|
goto FAIL;
|
|
|
|
|
|
|
|
|
|
status = csi_dictionary_put (ctx, dict, name.datum.name, &obj);
|
|
|
|
|
if (_csi_unlikely (status))
|
|
|
|
|
goto FAIL;
|
|
|
|
|
}
|
2008-11-13 11:07:45 +00:00
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
*out = dict;
|
2008-11-13 11:07:45 +00:00
|
|
|
return CSI_STATUS_SUCCESS;
|
2009-07-03 00:40:32 +01:00
|
|
|
|
|
|
|
|
FAIL:
|
|
|
|
|
csi_dictionary_free (ctx, dict);
|
|
|
|
|
return status;
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|
|
|
|
|
|
2009-07-03 00:40:32 +01:00
|
|
|
csi_status_t
|
|
|
|
|
_csi_translate_file (csi_t *ctx,
|
|
|
|
|
csi_file_t *file,
|
|
|
|
|
cairo_write_func_t write_func,
|
|
|
|
|
void *closure)
|
2008-11-13 11:07:45 +00:00
|
|
|
{
|
2009-07-03 00:40:32 +01:00
|
|
|
csi_status_t status;
|
|
|
|
|
struct _translate_closure translator;
|
|
|
|
|
|
2015-06-16 16:42:56 -07:00
|
|
|
if ((status = setjmp (ctx->scanner.jump_buffer)))
|
2009-07-03 00:40:32 +01:00
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
status = build_opcodes (ctx, &translator.opcodes);
|
|
|
|
|
if (_csi_unlikely (status))
|
|
|
|
|
return status;
|
|
|
|
|
|
|
|
|
|
translator.write_func = write_func;
|
|
|
|
|
translator.closure = closure;
|
|
|
|
|
ctx->scanner.closure = &translator;
|
|
|
|
|
|
2009-08-11 21:26:11 +01:00
|
|
|
ctx->scanner.bind = 1;
|
2009-07-03 00:40:32 +01:00
|
|
|
ctx->scanner.push = _translate_push;
|
|
|
|
|
ctx->scanner.execute = _translate_execute;
|
|
|
|
|
|
|
|
|
|
_scan_file (ctx, file);
|
|
|
|
|
|
2009-08-11 21:26:11 +01:00
|
|
|
ctx->scanner.bind = 0;
|
2009-07-03 00:40:32 +01:00
|
|
|
ctx->scanner.push = _scan_push;
|
|
|
|
|
ctx->scanner.execute = _scan_execute;
|
|
|
|
|
|
|
|
|
|
csi_dictionary_free (ctx, translator.opcodes);
|
|
|
|
|
|
|
|
|
|
return CSI_STATUS_SUCCESS;
|
2008-11-13 11:07:45 +00:00
|
|
|
}
|