SplashMath.h 6.5 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
// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
16 17 18 19 20 21
//
// 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
22 23 24
#ifndef SPLASHMATH_H
#define SPLASHMATH_H

25
#include "poppler-config.h"
26

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

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

static inline int splashFloor(SplashCoord x) {
45
#if defined(USE_FIXEDPOINT)
46
    return FixedPoint::floor(x);
47
#elif defined(USE_FLOAT)
48
    return (int)floorf(x);
49
#elif defined(__GNUC__) && defined(__i386__)
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
    // 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;
68
#elif defined(_WIN32) && defined(_M_IX86)
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
    // 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;
85
#else
86 87
    if (x > 0) return (int)x;
    else return (int)floor(x);
88
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
89 90 91
}

static inline int splashCeil(SplashCoord x) {
92
#if defined(USE_FIXEDPOINT)
93
  return FixedPoint::ceil(x);
94
#elif defined(USE_FLOAT)
95
  return (int)ceilf(x);
96
#elif defined(__GNUC__) && defined(__i386__)
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
  // 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;
115
#elif defined(_WIN32) && defined(_M_IX86)
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
  // 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;
132
#else
Kristian Høgsberg's avatar
Kristian Høgsberg committed
133
  return (int)ceil(x);
134
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
135 136 137
}

static inline int splashRound(SplashCoord x) {
138
#if defined(USE_FIXEDPOINT)
139
  return FixedPoint::round(x);
140
#elif defined(__GNUC__) && defined(__i386__)
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
  // 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;
160
#elif defined(_WIN32) && defined(_M_IX86)
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
  // 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;
178
#else
179
  return (int)splashFloor(x + 0.5);
180
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
181 182
}

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

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

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

236 237 238
static inline GBool splashCheckDet(SplashCoord m11, SplashCoord m12,
				   SplashCoord m21, SplashCoord m22,
				   SplashCoord epsilon) {
239
#ifdef USE_FIXEDPOINT
240 241 242 243 244 245
  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
246
#endif