Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygengdiplus.c
Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 2007 Google (Evan Stade) 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00017 */ 00018 00019 #include <stdarg.h> 00020 #include <math.h> 00021 00022 #include "windef.h" 00023 #include "winbase.h" 00024 #include "winerror.h" 00025 #include "wine/debug.h" 00026 #include "wingdi.h" 00027 00028 #include "objbase.h" 00029 00030 #include "winreg.h" 00031 #include "shlwapi.h" 00032 00033 #include "gdiplus.h" 00034 #include "gdiplus_private.h" 00035 00036 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus); 00037 00038 static Status WINAPI NotificationHook(ULONG_PTR *token) 00039 { 00040 TRACE("%p\n", token); 00041 if(!token) 00042 return InvalidParameter; 00043 00044 return Ok; 00045 } 00046 00047 static void WINAPI NotificationUnhook(ULONG_PTR token) 00048 { 00049 TRACE("%ld\n", token); 00050 } 00051 00052 /***************************************************** 00053 * DllMain 00054 */ 00055 BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) 00056 { 00057 TRACE("(%p, %d, %p)\n", hinst, reason, reserved); 00058 00059 switch(reason) 00060 { 00061 case DLL_PROCESS_ATTACH: 00062 DisableThreadLibraryCalls( hinst ); 00063 break; 00064 00065 case DLL_PROCESS_DETACH: 00066 free_installed_fonts(); 00067 break; 00068 } 00069 return TRUE; 00070 } 00071 00072 /***************************************************** 00073 * GdiplusStartup [GDIPLUS.@] 00074 */ 00075 Status WINAPI GdiplusStartup(ULONG_PTR *token, const struct GdiplusStartupInput *input, 00076 struct GdiplusStartupOutput *output) 00077 { 00078 if(!token || !input) 00079 return InvalidParameter; 00080 00081 TRACE("%p %p %p\n", token, input, output); 00082 TRACE("GdiplusStartupInput %d %p %d %d\n", input->GdiplusVersion, 00083 input->DebugEventCallback, input->SuppressBackgroundThread, 00084 input->SuppressExternalCodecs); 00085 00086 if(input->GdiplusVersion < 1 || input->GdiplusVersion > 2) 00087 return UnsupportedGdiplusVersion; 00088 00089 if(input->SuppressBackgroundThread){ 00090 if(!output) 00091 return InvalidParameter; 00092 00093 output->NotificationHook = NotificationHook; 00094 output->NotificationUnhook = NotificationUnhook; 00095 } 00096 00097 *token = 0xdeadbeef; 00098 00099 /* FIXME: DebugEventCallback ignored */ 00100 00101 return Ok; 00102 } 00103 00104 GpStatus WINAPI GdiplusNotificationHook(ULONG_PTR *token) 00105 { 00106 FIXME("%p\n", token); 00107 return NotificationHook(token); 00108 } 00109 00110 void WINAPI GdiplusNotificationUnhook(ULONG_PTR token) 00111 { 00112 FIXME("%ld\n", token); 00113 NotificationUnhook(token); 00114 } 00115 00116 /***************************************************** 00117 * GdiplusShutdown [GDIPLUS.@] 00118 */ 00119 ULONG WINAPI GdiplusShutdown_wrapper(ULONG_PTR token) 00120 { 00121 /* Notice the slightly different prototype from the official 00122 * signature which forces us to use the _wrapper suffix. 00123 */ 00124 00125 /* FIXME: no object tracking */ 00126 00127 /* "bricksntiles" expects a return value of 0, which native 00128 * coincidentally gives. 00129 */ 00130 return 0; 00131 } 00132 00133 /***************************************************** 00134 * GdipAlloc [GDIPLUS.@] 00135 */ 00136 void* WINGDIPAPI GdipAlloc(SIZE_T size) 00137 { 00138 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); 00139 } 00140 00141 /***************************************************** 00142 * GdipFree [GDIPLUS.@] 00143 */ 00144 void WINGDIPAPI GdipFree(void* ptr) 00145 { 00146 HeapFree(GetProcessHeap(), 0, ptr); 00147 } 00148 00149 /* Calculates the bezier points needed to fill in the arc portion starting at 00150 * angle start and ending at end. These two angles should be no more than 90 00151 * degrees from each other. x1, y1, x2, y2 describes the bounding box (upper 00152 * left and width and height). Angles must be in radians. write_first indicates 00153 * that the first bezier point should be written out (usually this is false). 00154 * pt is the array of GpPointFs that gets written to. 00155 **/ 00156 static void add_arc_part(GpPointF * pt, REAL x1, REAL y1, REAL x2, REAL y2, 00157 REAL start, REAL end, BOOL write_first) 00158 { 00159 REAL center_x, center_y, rad_x, rad_y, cos_start, cos_end, 00160 sin_start, sin_end, a, half; 00161 INT i; 00162 00163 rad_x = x2 / 2.0; 00164 rad_y = y2 / 2.0; 00165 center_x = x1 + rad_x; 00166 center_y = y1 + rad_y; 00167 00168 cos_start = cos(start); 00169 cos_end = cos(end); 00170 sin_start = sin(start); 00171 sin_end = sin(end); 00172 00173 half = (end - start) / 2.0; 00174 a = 4.0 / 3.0 * (1 - cos(half)) / sin(half); 00175 00176 if(write_first){ 00177 pt[0].X = cos_start; 00178 pt[0].Y = sin_start; 00179 } 00180 pt[1].X = cos_start - a * sin_start; 00181 pt[1].Y = sin_start + a * cos_start; 00182 00183 pt[3].X = cos_end; 00184 pt[3].Y = sin_end; 00185 pt[2].X = cos_end + a * sin_end; 00186 pt[2].Y = sin_end - a * cos_end; 00187 00188 /* expand the points back from the unit circle to the ellipse */ 00189 for(i = (write_first ? 0 : 1); i < 4; i ++){ 00190 pt[i].X = pt[i].X * rad_x + center_x; 00191 pt[i].Y = pt[i].Y * rad_y + center_y; 00192 } 00193 } 00194 00195 /* We plot the curve as if it is on a circle then stretch the points. This 00196 * adjusts the angles so that when we stretch the points they will end in the 00197 * right place. This is only complicated because atan and atan2 do not behave 00198 * conveniently. */ 00199 static void unstretch_angle(REAL * angle, REAL rad_x, REAL rad_y) 00200 { 00201 REAL stretched; 00202 INT revs_off; 00203 00204 *angle = deg2rad(*angle); 00205 00206 if(fabs(cos(*angle)) < 0.00001 || fabs(sin(*angle)) < 0.00001) 00207 return; 00208 00209 stretched = gdiplus_atan2(sin(*angle) / fabs(rad_y), cos(*angle) / fabs(rad_x)); 00210 revs_off = roundr(*angle / (2.0 * M_PI)) - roundr(stretched / (2.0 * M_PI)); 00211 stretched += ((REAL)revs_off) * M_PI * 2.0; 00212 *angle = stretched; 00213 } 00214 00215 /* Stores the bezier points that correspond to the arc in points. If points is 00216 * null, just return the number of points needed to represent the arc. */ 00217 INT arc2polybezier(GpPointF * points, REAL x1, REAL y1, REAL x2, REAL y2, 00218 REAL startAngle, REAL sweepAngle) 00219 { 00220 INT i; 00221 REAL end_angle, start_angle, endAngle; 00222 00223 endAngle = startAngle + sweepAngle; 00224 unstretch_angle(&startAngle, x2 / 2.0, y2 / 2.0); 00225 unstretch_angle(&endAngle, x2 / 2.0, y2 / 2.0); 00226 00227 /* start_angle and end_angle are the iterative variables */ 00228 start_angle = startAngle; 00229 00230 for(i = 0; i < MAX_ARC_PTS - 1; i += 3){ 00231 /* check if we've overshot the end angle */ 00232 if( sweepAngle > 0.0 ) 00233 { 00234 if (start_angle >= endAngle) break; 00235 end_angle = min(start_angle + M_PI_2, endAngle); 00236 } 00237 else 00238 { 00239 if (start_angle <= endAngle) break; 00240 end_angle = max(start_angle - M_PI_2, endAngle); 00241 } 00242 00243 if (points) 00244 add_arc_part(&points[i], x1, y1, x2, y2, start_angle, end_angle, i == 0); 00245 00246 start_angle += M_PI_2 * (sweepAngle < 0.0 ? -1.0 : 1.0); 00247 } 00248 00249 if (i == 0) return 0; 00250 else return i+1; 00251 } 00252 00253 COLORREF ARGB2COLORREF(ARGB color) 00254 { 00255 /* 00256 Packing of these color structures: 00257 COLORREF: 00bbggrr 00258 ARGB: aarrggbb 00259 FIXME:doesn't handle alpha channel 00260 */ 00261 return ((color & 0x0000ff) << 16) + 00262 (color & 0x00ff00) + 00263 ((color & 0xff0000) >> 16); 00264 } 00265 00266 HBITMAP ARGB2BMP(ARGB color) 00267 { 00268 BITMAPINFO bi; 00269 HBITMAP result; 00270 RGBQUAD *bits; 00271 int alpha; 00272 00273 if ((color & 0xff000000) == 0xff000000) return 0; 00274 00275 bi.bmiHeader.biSize = sizeof(bi.bmiHeader); 00276 bi.bmiHeader.biWidth = 1; 00277 bi.bmiHeader.biHeight = 1; 00278 bi.bmiHeader.biPlanes = 1; 00279 bi.bmiHeader.biBitCount = 32; 00280 bi.bmiHeader.biCompression = BI_RGB; 00281 bi.bmiHeader.biSizeImage = 0; 00282 bi.bmiHeader.biXPelsPerMeter = 0; 00283 bi.bmiHeader.biYPelsPerMeter = 0; 00284 bi.bmiHeader.biClrUsed = 0; 00285 bi.bmiHeader.biClrImportant = 0; 00286 00287 result = CreateDIBSection(0, &bi, DIB_RGB_COLORS, (void*)&bits, NULL, 0); 00288 00289 bits[0].rgbReserved = alpha = (color>>24)&0xff; 00290 bits[0].rgbRed = ((color>>16)&0xff)*alpha/255; 00291 bits[0].rgbGreen = ((color>>8)&0xff)*alpha/255; 00292 bits[0].rgbBlue = (color&0xff)*alpha/255; 00293 00294 return result; 00295 } 00296 00297 /* Like atan2, but puts angle in correct quadrant if dx is 0. */ 00298 REAL gdiplus_atan2(REAL dy, REAL dx) 00299 { 00300 if((dx == 0.0) && (dy != 0.0)) 00301 return dy > 0.0 ? M_PI_2 : -M_PI_2; 00302 00303 return atan2(dy, dx); 00304 } 00305 00306 GpStatus hresult_to_status(HRESULT res) 00307 { 00308 switch(res){ 00309 case S_OK: 00310 return Ok; 00311 case E_OUTOFMEMORY: 00312 return OutOfMemory; 00313 case E_INVALIDARG: 00314 return InvalidParameter; 00315 default: 00316 return GenericError; 00317 } 00318 } 00319 00320 /* converts a given unit to its value in pixels */ 00321 REAL convert_unit(REAL logpixels, GpUnit unit) 00322 { 00323 switch(unit) 00324 { 00325 case UnitInch: 00326 return logpixels; 00327 case UnitPoint: 00328 return logpixels / 72.0; 00329 case UnitDocument: 00330 return logpixels / 300.0; 00331 case UnitMillimeter: 00332 return logpixels / 25.4; 00333 case UnitWorld: 00334 ERR("cannot convert UnitWorld\n"); 00335 return 0.0; 00336 case UnitPixel: 00337 case UnitDisplay: 00338 default: 00339 return 1.0; 00340 } 00341 } 00342 00343 /* Calculates Bezier points from cardinal spline points. */ 00344 void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1, 00345 REAL *y1, REAL *x2, REAL *y2) 00346 { 00347 REAL xdiff, ydiff; 00348 00349 /* calculate tangent */ 00350 xdiff = pts[2].X - pts[0].X; 00351 ydiff = pts[2].Y - pts[0].Y; 00352 00353 /* apply tangent to get control points */ 00354 *x1 = pts[1].X - tension * xdiff; 00355 *y1 = pts[1].Y - tension * ydiff; 00356 *x2 = pts[1].X + tension * xdiff; 00357 *y2 = pts[1].Y + tension * ydiff; 00358 } 00359 00360 /* Calculates Bezier points from cardinal spline endpoints. */ 00361 void calc_curve_bezier_endp(REAL xend, REAL yend, REAL xadj, REAL yadj, 00362 REAL tension, REAL *x, REAL *y) 00363 { 00364 /* tangent at endpoints is the line from the endpoint to the adjacent point */ 00365 *x = roundr(tension * (xadj - xend) + xend); 00366 *y = roundr(tension * (yadj - yend) + yend); 00367 } 00368 00369 /* make sure path has enough space for len more points */ 00370 BOOL lengthen_path(GpPath *path, INT len) 00371 { 00372 /* initial allocation */ 00373 if(path->datalen == 0){ 00374 path->datalen = len * 2; 00375 00376 path->pathdata.Points = GdipAlloc(path->datalen * sizeof(PointF)); 00377 if(!path->pathdata.Points) return FALSE; 00378 00379 path->pathdata.Types = GdipAlloc(path->datalen); 00380 if(!path->pathdata.Types){ 00381 GdipFree(path->pathdata.Points); 00382 return FALSE; 00383 } 00384 } 00385 /* reallocation, double size of arrays */ 00386 else if(path->datalen - path->pathdata.Count < len){ 00387 while(path->datalen - path->pathdata.Count < len) 00388 path->datalen *= 2; 00389 00390 path->pathdata.Points = HeapReAlloc(GetProcessHeap(), 0, 00391 path->pathdata.Points, path->datalen * sizeof(PointF)); 00392 if(!path->pathdata.Points) return FALSE; 00393 00394 path->pathdata.Types = HeapReAlloc(GetProcessHeap(), 0, 00395 path->pathdata.Types, path->datalen); 00396 if(!path->pathdata.Types) return FALSE; 00397 } 00398 00399 return TRUE; 00400 } 00401 00402 void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height, 00403 BYTE *dst_bits, INT dst_stride, const BYTE *src_bits, INT src_stride) 00404 { 00405 INT x, y; 00406 for (y=0; y<height; y++) 00407 { 00408 const BYTE *src=src_bits+y*src_stride; 00409 BYTE *dst=dst_bits+y*dst_stride; 00410 for (x=0; x<width; x++) 00411 { 00412 BYTE alpha=src[3]; 00413 *dst++ = *src++ * alpha / 255; 00414 *dst++ = *src++ * alpha / 255; 00415 *dst++ = *src++ * alpha / 255; 00416 *dst++ = *src++; 00417 } 00418 } 00419 } 00420 00421 /* recursive deletion of GpRegion nodes */ 00422 void delete_element(region_element* element) 00423 { 00424 switch(element->type) 00425 { 00426 case RegionDataRect: 00427 break; 00428 case RegionDataPath: 00429 GdipDeletePath(element->elementdata.pathdata.path); 00430 break; 00431 case RegionDataEmptyRect: 00432 case RegionDataInfiniteRect: 00433 break; 00434 default: 00435 delete_element(element->elementdata.combine.left); 00436 delete_element(element->elementdata.combine.right); 00437 GdipFree(element->elementdata.combine.left); 00438 GdipFree(element->elementdata.combine.right); 00439 break; 00440 } 00441 } 00442 00443 const char *debugstr_rectf(CONST RectF* rc) 00444 { 00445 if (!rc) return "(null)"; 00446 return wine_dbg_sprintf("(%0.2f,%0.2f,%0.2f,%0.2f)", rc->X, rc->Y, rc->Width, rc->Height); 00447 } 00448 00449 const char *debugstr_pointf(CONST PointF* pt) 00450 { 00451 if (!pt) return "(null)"; 00452 return wine_dbg_sprintf("(%0.2f,%0.2f)", pt->X, pt->Y); 00453 } Generated on Sun May 27 2012 04:23:34 for ReactOS by
1.7.6.1
|