|  | /* | 
|  | * Copyright (C) 2007 Google (Evan Stade) | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include <stdarg.h> | 
|  | #include <math.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "wingdi.h" | 
|  |  | 
|  | #include "objbase.h" | 
|  |  | 
|  | #include "gdiplus.h" | 
|  | #include "gdiplus_private.h" | 
|  |  | 
|  | /* Multiplies two matrices of the form | 
|  | * | 
|  | * idx:0 idx:1     0 | 
|  | * idx:2 idx:3     0 | 
|  | * idx:4 idx:5     1 | 
|  | * | 
|  | * and puts the output in out. | 
|  | * */ | 
|  | static void matrix_multiply(GDIPCONST REAL * left, GDIPCONST REAL * right, REAL * out) | 
|  | { | 
|  | REAL temp[6]; | 
|  | int i, odd; | 
|  |  | 
|  | for(i = 0; i < 6; i++){ | 
|  | odd = i % 2; | 
|  | temp[i] = left[i - odd] * right[odd] + left[i - odd + 1] * right[odd + 2] + | 
|  | (i >= 4 ? right[odd + 4] : 0.0); | 
|  | } | 
|  |  | 
|  | memcpy(out, temp, 6 * sizeof(REAL)); | 
|  | } | 
|  |  | 
|  | GpStatus WINGDIPAPI GdipCreateMatrix2(REAL m11, REAL m12, REAL m21, REAL m22, | 
|  | REAL dx, REAL dy, GpMatrix **matrix) | 
|  | { | 
|  | if(!matrix) | 
|  | return InvalidParameter; | 
|  |  | 
|  | *matrix = GdipAlloc(sizeof(GpMatrix)); | 
|  | if(!*matrix)    return OutOfMemory; | 
|  |  | 
|  | /* first row */ | 
|  | (*matrix)->matrix[0] = m11; | 
|  | (*matrix)->matrix[1] = m12; | 
|  | /* second row */ | 
|  | (*matrix)->matrix[2] = m21; | 
|  | (*matrix)->matrix[3] = m22; | 
|  | /* third row */ | 
|  | (*matrix)->matrix[4] = dx; | 
|  | (*matrix)->matrix[5] = dy; | 
|  |  | 
|  | return Ok; | 
|  | } | 
|  |  | 
|  | GpStatus WINGDIPAPI GdipCreateMatrix3(GDIPCONST GpRectF *rect, | 
|  | GDIPCONST GpPointF *pt, GpMatrix **matrix) | 
|  | { | 
|  | if(!matrix) | 
|  | return InvalidParameter; | 
|  |  | 
|  | *matrix = GdipAlloc(sizeof(GpMatrix)); | 
|  | if(!*matrix)    return OutOfMemory; | 
|  |  | 
|  | memcpy((*matrix)->matrix, rect, 4 * sizeof(REAL)); | 
|  |  | 
|  | (*matrix)->matrix[4] = pt->X; | 
|  | (*matrix)->matrix[5] = pt->Y; | 
|  |  | 
|  | return Ok; | 
|  | } | 
|  |  | 
|  | GpStatus WINGDIPAPI GdipCloneMatrix(GpMatrix *matrix, GpMatrix **clone) | 
|  | { | 
|  | if(!matrix || !clone) | 
|  | return InvalidParameter; | 
|  |  | 
|  | *clone = GdipAlloc(sizeof(GpMatrix)); | 
|  | if(!*clone)    return OutOfMemory; | 
|  |  | 
|  | memcpy(*clone, matrix, sizeof(GpMatrix)); | 
|  |  | 
|  | return Ok; | 
|  | } | 
|  |  | 
|  | GpStatus WINGDIPAPI GdipCreateMatrix(GpMatrix **matrix) | 
|  | { | 
|  | if(!matrix) | 
|  | return InvalidParameter; | 
|  |  | 
|  | *matrix = GdipAlloc(sizeof(GpMatrix)); | 
|  | if(!*matrix)    return OutOfMemory; | 
|  |  | 
|  | (*matrix)->matrix[0] = 1.0; | 
|  | (*matrix)->matrix[1] = 0.0; | 
|  | (*matrix)->matrix[2] = 0.0; | 
|  | (*matrix)->matrix[3] = 1.0; | 
|  | (*matrix)->matrix[4] = 0.0; | 
|  | (*matrix)->matrix[5] = 0.0; | 
|  |  | 
|  | return Ok; | 
|  | } | 
|  |  | 
|  | GpStatus WINGDIPAPI GdipDeleteMatrix(GpMatrix *matrix) | 
|  | { | 
|  | if(!matrix) | 
|  | return InvalidParameter; | 
|  |  | 
|  | GdipFree(matrix); | 
|  |  | 
|  | return Ok; | 
|  | } | 
|  |  | 
|  | GpStatus WINGDIPAPI GdipGetMatrixElements(GDIPCONST GpMatrix *matrix, | 
|  | REAL *out) | 
|  | { | 
|  | if(!matrix || !out) | 
|  | return InvalidParameter; | 
|  |  | 
|  | memcpy(out, matrix->matrix, sizeof(matrix->matrix)); | 
|  |  | 
|  | return Ok; | 
|  | } | 
|  |  | 
|  | GpStatus WINGDIPAPI GdipMultiplyMatrix(GpMatrix *matrix, GpMatrix* matrix2, | 
|  | GpMatrixOrder order) | 
|  | { | 
|  | if(!matrix || !matrix2) | 
|  | return InvalidParameter; | 
|  |  | 
|  | if(order == MatrixOrderAppend) | 
|  | matrix_multiply(matrix->matrix, matrix2->matrix, matrix->matrix); | 
|  | else | 
|  | matrix_multiply(matrix2->matrix, matrix->matrix, matrix->matrix); | 
|  |  | 
|  | return Ok; | 
|  | } | 
|  |  | 
|  | GpStatus WINGDIPAPI GdipRotateMatrix(GpMatrix *matrix, REAL angle, | 
|  | GpMatrixOrder order) | 
|  | { | 
|  | REAL cos_theta, sin_theta, rotate[6]; | 
|  |  | 
|  | if(!matrix) | 
|  | return InvalidParameter; | 
|  |  | 
|  | angle = deg2rad(angle); | 
|  | cos_theta = cos(angle); | 
|  | sin_theta = sin(angle); | 
|  |  | 
|  | rotate[0] = cos_theta; | 
|  | rotate[1] = sin_theta; | 
|  | rotate[2] = -sin_theta; | 
|  | rotate[3] = cos_theta; | 
|  | rotate[4] = 0.0; | 
|  | rotate[5] = 0.0; | 
|  |  | 
|  | if(order == MatrixOrderAppend) | 
|  | matrix_multiply(matrix->matrix, rotate, matrix->matrix); | 
|  | else | 
|  | matrix_multiply(rotate, matrix->matrix, matrix->matrix); | 
|  |  | 
|  | return Ok; | 
|  | } | 
|  |  | 
|  | GpStatus WINGDIPAPI GdipScaleMatrix(GpMatrix *matrix, REAL scaleX, REAL scaleY, | 
|  | GpMatrixOrder order) | 
|  | { | 
|  | REAL scale[6]; | 
|  |  | 
|  | if(!matrix) | 
|  | return InvalidParameter; | 
|  |  | 
|  | scale[0] = scaleX; | 
|  | scale[1] = 0.0; | 
|  | scale[2] = 0.0; | 
|  | scale[3] = scaleY; | 
|  | scale[4] = 0.0; | 
|  | scale[5] = 0.0; | 
|  |  | 
|  | if(order == MatrixOrderAppend) | 
|  | matrix_multiply(matrix->matrix, scale, matrix->matrix); | 
|  | else | 
|  | matrix_multiply(scale, matrix->matrix, matrix->matrix); | 
|  |  | 
|  | return Ok; | 
|  | } | 
|  |  | 
|  | GpStatus WINGDIPAPI GdipSetMatrixElements(GpMatrix *matrix, REAL m11, REAL m12, | 
|  | REAL m21, REAL m22, REAL dx, REAL dy) | 
|  | { | 
|  | if(!matrix) | 
|  | return InvalidParameter; | 
|  |  | 
|  | matrix->matrix[0] = m11; | 
|  | matrix->matrix[1] = m12; | 
|  | matrix->matrix[2] = m21; | 
|  | matrix->matrix[3] = m22; | 
|  | matrix->matrix[4] = dx; | 
|  | matrix->matrix[5] = dy; | 
|  |  | 
|  | return Ok; | 
|  | } | 
|  |  | 
|  | GpStatus WINGDIPAPI GdipTransformMatrixPoints(GpMatrix *matrix, GpPointF *pts, | 
|  | INT count) | 
|  | { | 
|  | REAL x, y; | 
|  | INT i; | 
|  |  | 
|  | if(!matrix || !pts) | 
|  | return InvalidParameter; | 
|  |  | 
|  | for(i = 0; i < count; i++) | 
|  | { | 
|  | x = pts[i].X; | 
|  | y = pts[i].Y; | 
|  |  | 
|  | pts[i].X = x * matrix->matrix[0] + y * matrix->matrix[2] + matrix->matrix[4]; | 
|  | pts[i].Y = x * matrix->matrix[1] + y * matrix->matrix[3] + matrix->matrix[5]; | 
|  | } | 
|  |  | 
|  | return Ok; | 
|  | } | 
|  |  | 
|  | GpStatus WINGDIPAPI GdipTranslateMatrix(GpMatrix *matrix, REAL offsetX, | 
|  | REAL offsetY, GpMatrixOrder order) | 
|  | { | 
|  | REAL translate[6]; | 
|  |  | 
|  | if(!matrix) | 
|  | return InvalidParameter; | 
|  |  | 
|  | translate[0] = 1.0; | 
|  | translate[1] = 0.0; | 
|  | translate[2] = 0.0; | 
|  | translate[3] = 1.0; | 
|  | translate[4] = offsetX; | 
|  | translate[5] = offsetY; | 
|  |  | 
|  | if(order == MatrixOrderAppend) | 
|  | matrix_multiply(matrix->matrix, translate, matrix->matrix); | 
|  | else | 
|  | matrix_multiply(translate, matrix->matrix, matrix->matrix); | 
|  |  | 
|  | return Ok; | 
|  | } |