SplashMath.h 6.44 KB
Newer Older
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1 2 3 4 5 6
//========================================================================
//
// SplashMath.h
//
//========================================================================

7 8 9 10 11 12 13
//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
14
// Copyright (C) 2009-2011 Albert Astals Cid <aacid@kde.org>
15 16 17 18 19 20
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================

Kristian Høgsberg's avatar
Kristian Høgsberg committed
21 22 23
#ifndef SPLASHMATH_H
#define SPLASHMATH_H

24
#include "poppler-config.h"
25

26
#ifdef USE_FIXEDPOINT
27
#include "goo/FixedPoint.h"
28
#else
Kristian Høgsberg's avatar
Kristian Høgsberg committed
29
#include <math.h>
30
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
31 32 33
#include "SplashTypes.h"

static inline SplashCoord splashAbs(SplashCoord x) {
34
#if defined(USE_FIXEDPOINT)
35
  return FixedPoint::abs(x);
36
#elif defined(USE_FLOAT)
37
  return fabsf(x);
38
#else
Kristian Høgsberg's avatar
Kristian Høgsberg committed
39
  return fabs(x);
40
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
41 42 43
}

static inline int splashFloor(SplashCoord x) {
44
#if defined(USE_FIXEDPOINT)
45
    return FixedPoint::floor(x);
46
#elif defined(USE_FLOAT)
47
    return (int)floorf(x);
48
#elif defined(__GNUC__) && defined(__i386__)
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
    // floor() and (int)() are implemented separately, which results
    // in changing the FPCW multiple times - so we optimize it with
    // some inline assembly
    Gushort oldCW, newCW, t;
    int result;

    __asm__ volatile("fldl   %4\n"
		   "fnstcw %0\n"
		   "movw   %0, %3\n"
		   "andw   $0xf3ff, %3\n"
		   "orw    $0x0400, %3\n"
		   "movw   %3, %1\n"       // round down
		   "fldcw  %1\n"
		   "fistpl %2\n"
		   "fldcw  %0\n"
		   : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t)
		   : "m" (x));
    return result;
67
#elif defined(_WIN32) && defined(_M_IX86)
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
    // floor() and (int)() are implemented separately, which results
    // in changing the FPCW multiple times - so we optimize it with
    // some inline assembly
    Gushort oldCW, newCW;
    int result;

    __asm fld QWORD PTR x
    __asm fnstcw WORD PTR oldCW
    __asm mov ax, WORD PTR oldCW
    __asm and ax, 0xf3ff
    __asm or ax, 0x0400
    __asm mov WORD PTR newCW, ax     // round down
    __asm fldcw WORD PTR newCW
    __asm fistp DWORD PTR result
    __asm fldcw WORD PTR oldCW
    return result;
84
#else
85 86
    if (x > 0) return (int)x;
    else return (int)floor(x);
87
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
88 89 90
}

static inline int splashCeil(SplashCoord x) {
91
#if defined(USE_FIXEDPOINT)
92
  return FixedPoint::ceil(x);
93
#elif defined(USE_FLOAT)
94
  return (int)ceilf(x);
95
#elif defined(__GNUC__) && defined(__i386__)
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
  // ceil() and (int)() are implemented separately, which results
  // in changing the FPCW multiple times - so we optimize it with
  // some inline assembly
  Gushort oldCW, newCW, t;
  int result;

  __asm__ volatile("fldl   %4\n"
		   "fnstcw %0\n"
		   "movw   %0, %3\n"
		   "andw   $0xf3ff, %3\n"
		   "orw    $0x0800, %3\n"
		   "movw   %3, %1\n"       // round up
		   "fldcw  %1\n"
		   "fistpl %2\n"
		   "fldcw  %0\n"
		   : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t)
		   : "m" (x));
  return result;
114
#elif defined(_WIN32) && defined(_M_IX86)
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
  // ceil() and (int)() are implemented separately, which results
  // in changing the FPCW multiple times - so we optimize it with
  // some inline assembly
  Gushort oldCW, newCW;
  int result;

  __asm fld QWORD PTR x
  __asm fnstcw WORD PTR oldCW
  __asm mov ax, WORD PTR oldCW
  __asm and ax, 0xf3ff
  __asm or ax, 0x0800
  __asm mov WORD PTR newCW, ax     // round up
  __asm fldcw WORD PTR newCW
  __asm fistp DWORD PTR result
  __asm fldcw WORD PTR oldCW
  return result;
131
#else
Kristian Høgsberg's avatar
Kristian Høgsberg committed
132
  return (int)ceil(x);
133
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
134 135 136
}

static inline int splashRound(SplashCoord x) {
137
#if defined(USE_FIXEDPOINT)
138
  return FixedPoint::round(x);
139
#elif defined(__GNUC__) && defined(__i386__)
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
  // this could use round-to-nearest mode and avoid the "+0.5",
  // but that produces slightly different results (because i+0.5
  // sometimes rounds up and sometimes down using the even rule)
  Gushort oldCW, newCW, t;
  int result;

  x += 0.5;
  __asm__ volatile("fldl   %4\n"
		   "fnstcw %0\n"
		   "movw   %0, %3\n"
		   "andw   $0xf3ff, %3\n"
		   "orw    $0x0400, %3\n"
		   "movw   %3, %1\n"       // round down
		   "fldcw  %1\n"
		   "fistpl %2\n"
		   "fldcw  %0\n"
		   : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t)
		   : "m" (x));
  return result;
159
#elif defined(_WIN32) && defined(_M_IX86)
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
  // this could use round-to-nearest mode and avoid the "+0.5",
  // but that produces slightly different results (because i+0.5
  // sometimes rounds up and sometimes down using the even rule)
  Gushort oldCW, newCW;
  int result;

  x += 0.5;
  __asm fld QWORD PTR x
  __asm fnstcw WORD PTR oldCW
  __asm mov ax, WORD PTR oldCW
  __asm and ax, 0xf3ff
  __asm or ax, 0x0400
  __asm mov WORD PTR newCW, ax     // round down
  __asm fldcw WORD PTR newCW
  __asm fistp DWORD PTR result
  __asm fldcw WORD PTR oldCW
  return result;
177
#else
178
  return (int)splashFloor(x + 0.5);
179
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
180 181
}

182
static inline SplashCoord splashAvg(SplashCoord x, SplashCoord y) {
183
#ifdef USE_FIXEDPOINT
184 185 186 187 188 189
  return FixedPoint::avg(x, y);
#else
  return 0.5 * (x + y);
#endif
}
 
Kristian Høgsberg's avatar
Kristian Høgsberg committed
190
static inline SplashCoord splashSqrt(SplashCoord x) {
191
#if defined(USE_FIXEDPOINT)
192
  return FixedPoint::sqrt(x);
193
#elif defined(USE_FLOAT)
194
  return sqrtf(x);
195
#else
Kristian Høgsberg's avatar
Kristian Høgsberg committed
196
  return sqrt(x);
197
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
198 199 200
}

static inline SplashCoord splashPow(SplashCoord x, SplashCoord y) {
201
#if defined(USE_FIXEDPOINT)
202
  return FixedPoint::pow(x, y);
203
#elif defined(USE_FLOAT)
204
  return powf(x, y);
205
#else
Kristian Høgsberg's avatar
Kristian Høgsberg committed
206
  return pow(x, y);
207
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
208 209 210 211 212 213 214
}

static inline SplashCoord splashDist(SplashCoord x0, SplashCoord y0,
				     SplashCoord x1, SplashCoord y1) {
  SplashCoord dx, dy;
  dx = x1 - x0;
  dy = y1 - y0;
215
#ifdef USE_FIXEDPOINT
216 217
  // this handles the situation where dx*dx or dy*dy is too large to
  // fit in the 16.16 fixed point format
218
  SplashCoord dxa, dya, d;
219 220 221 222 223
  dxa = splashAbs(dx);
  dya = splashAbs(dy);
  if (dxa == 0 && dya == 0) {
    return 0;
  } else if (dxa > dya) {
224 225
    d = dya / dxa;
    return dxa * FixedPoint::sqrt(d*d + 1);
226
  } else {
227 228
    d = dxa / dya;
    return dya * FixedPoint::sqrt(d*d + 1);
229
  }
230
#else
231
  return splashSqrt(dx * dx + dy * dy);
232
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
233 234
}

235 236 237
static inline GBool splashCheckDet(SplashCoord m11, SplashCoord m12,
				   SplashCoord m21, SplashCoord m22,
				   SplashCoord epsilon) {
238
#ifdef USE_FIXEDPOINT
239 240 241 242 243 244
  return FixedPoint::checkDet(m11, m12, m21, m22, epsilon);
#else
  return fabs(m11 * m22 - m12 * m21) >= epsilon;
#endif
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
245
#endif