/* Implementation of GUI terminal on the Microsoft Windows API.
Copyright (C) 1989, 1993-2020 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
GNU Emacs 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see . */
#include
#include "lisp.h"
#include "dispextern.h"
#define COBJMACROS
#include
#include
#include
#include
#include "w32term.h"
#include "frame.h"
#include "coding.h"
static int
gdiplus_initialized_p()
{
static int gdip_initialized = 0;
static ULONG_PTR token;
static GdiplusStartupInput input;
static GdiplusStartupOutput output;
GpStatus status;
if (gdip_initialized < 0)
{
return 0;
}
else if (gdip_initialized)
{
return 1;
}
else
{
input.GdiplusVersion = 1;
input.DebugEventCallback = NULL;
input.SuppressBackgroundThread = FALSE;
input.SuppressExternalCodecs = FALSE;
status = GdiplusStartup(&token, &input, &output);
if (status == Ok)
{
gdip_initialized = 1;
return 1;
}
else
{
gdip_initialized = -1;
return 0;
}
}
return 1;
}
static float
w32_frame_delay(GpBitmap *pBitmap, int frame)
{
UINT size;
PropertyItem *propertyItem;
float delay = 0.0;
// Assume that the image has a property item of type PropertyItemEquipMake.
// Get the size of that property item.
GdipGetPropertyItemSize(pBitmap, PropertyTagFrameDelay, &size);
// Allocate a buffer to receive the property item.
propertyItem = (PropertyItem*)malloc(size);
if (propertyItem != NULL)
{
// Get the property item.
GdipGetPropertyItem(pBitmap, PropertyTagFrameDelay, size, propertyItem);
delay = ((float)propertyItem[frame].length) / 100;
if (delay == 0)
{
/* In GIF files, unfortunately, delay is only specified for
the first frame */
delay = ((float)propertyItem[0].length) / 100;
}
// Free space
free(propertyItem);
}
return delay;
}
static UINT
w32_select_active_frame(GpBitmap *pBitmap, int frame, int *nframes, float *delay)
{
UINT count, frameCount;
GUID pDimensionIDs[1];
GpStatus status = Ok;
status = GdipImageGetFrameDimensionsCount(pBitmap, &count);
frameCount = *nframes = 0;
*delay = 0.0;
if (count)
{
status = GdipImageGetFrameDimensionsList(pBitmap, pDimensionIDs, 1);
status = GdipImageGetFrameCount(pBitmap, &pDimensionIDs[0], &frameCount);
fprintf(stderr, "FrameCount: %d\n", (int)frameCount);
fprintf(stderr, " index: %d\n", frame);
if ((status == Ok) && (frameCount > 1))
{
if (frame < 0 || frame >= frameCount)
{
status = GenericError;
}
else
{
status = GdipImageSelectActiveFrame(pBitmap, &pDimensionIDs[0], frame);
*delay = w32_frame_delay(pBitmap, frame);
*nframes = frameCount;
}
}
}
return status;
}
static ARGB
w32_image_bg_color(struct frame *f, struct image *img)
{
/* png_color_16 *image_bg; */
Lisp_Object specified_bg
= Fplist_get (XCDR (img->spec), QCbackground);
Emacs_Color color;
/* If the user specified a color, try to use it; if not, use the
current frame background, ignoring any default background
color set by the image. */
if (STRINGP (specified_bg)
? FRAME_TERMINAL (f)->defined_color_hook (f,
SSDATA (specified_bg),
&color,
false,
false)
: (FRAME_TERMINAL (f)->query_frame_background_color (f, &color),
true))
/* The user specified `:background', use that. */
{
DWORD red = (((DWORD) color.red) & 0xff00) << 8;
DWORD green = ((DWORD) color.green) & 0xff00;
DWORD blue = ((DWORD) color.blue) >> 8;
return red | green | blue;
}
return ((DWORD) 0xff000000);
}
int
w32_load_image (struct frame *f, struct image *img,
Lisp_Object spec_file, Lisp_Object spec_data)
{
Emacs_Pixmap pixmap;
GpStatus status = GenericError;
GpBitmap *pBitmap;
wchar_t filename[MAX_PATH];
ARGB bg_color;
Lisp_Object lisp_index, metadata;
unsigned int index, nframes;
float delay;
eassert (valid_image_p (img->spec));
if (!gdiplus_initialized_p ())
{
return 0;
}
if (STRINGP (spec_file))
{
filename_to_utf16 (SSDATA (spec_file) , filename);
status = GdipCreateBitmapFromFile (filename, &pBitmap);
}
else if (STRINGP (spec_data))
{
IStream *pStream = SHCreateMemStream ((BYTE *) SSDATA (spec_data),
SBYTES (spec_data));
if (pStream != NULL)
{
status = GdipCreateBitmapFromStream (pStream, &pBitmap);
IStream_Release(pStream);
}
}
metadata = Qnil;
if (status == Ok)
{
/* In multiframe pictures, select the first one */
lisp_index = Fplist_get (XCDR (img->spec), QCindex);
index = FIXNUMP (lisp_index) ? XFIXNAT (lisp_index) : 0;
status = w32_select_active_frame (pBitmap, index, &nframes, &delay);
if ((status == Ok))
{
if (nframes > 1)
metadata = Fcons (Qcount, Fcons (make_fixnum (nframes), metadata));
if (delay)
metadata = Fcons (Qdelay, Fcons (make_float (delay), metadata));
}
}
if (status == Ok)
{
bg_color = w32_image_bg_color(f, img);
status = GdipCreateHBITMAPFromBitmap (pBitmap, &pixmap, bg_color);
if (status == Ok)
{
UINT width, height;
GdipGetImageWidth (pBitmap, &width);
GdipGetImageHeight (pBitmap, &height);
img->width = width;
img->height = height;
img->pixmap = pixmap;
img->lisp_data = metadata;
}
GdipDisposeImage (pBitmap);
}
if (status != Ok)
{
add_to_log ("Unable to load image %s", img->spec);
return 0;
}
return 1;
}