mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-18 12:05:14 -04:00
Get the client compiling with xcode and running on OSX.
Still need to find a more efficient way of drawing the launcher..
This commit is contained in:
parent
6fbe7e161a
commit
b82354daa0
@ -43,7 +43,6 @@ typedef signed __int64 int64_t;
|
|||||||
|
|
||||||
typedef uint16_t Codepoint;
|
typedef uint16_t Codepoint;
|
||||||
typedef uint8_t bool;
|
typedef uint8_t bool;
|
||||||
typedef uint8_t bool;
|
|
||||||
#define true 1
|
#define true 1
|
||||||
#define false 0
|
#define false 0
|
||||||
#ifndef NULL
|
#ifndef NULL
|
||||||
|
@ -85,10 +85,10 @@ static void HeldBlockRenderer_SetBaseOffset(void) {
|
|||||||
Vector3 normalOffset = { 0.56f, -0.72f, -0.72f };
|
Vector3 normalOffset = { 0.56f, -0.72f, -0.72f };
|
||||||
Vector3 spriteOffset = { 0.46f, -0.52f, -0.72f };
|
Vector3 spriteOffset = { 0.46f, -0.52f, -0.72f };
|
||||||
Vector3 offset = sprite ? spriteOffset : normalOffset;
|
Vector3 offset = sprite ? spriteOffset : normalOffset;
|
||||||
|
|
||||||
Vector3_Add(&held_entity.Position, &held_entity.Position, &offset);
|
Vector3_AddBy(&held_entity.Position, &offset);
|
||||||
if (!sprite && Blocks.Draw[held_block] != DRAW_GAS) {
|
if (!sprite && Blocks.Draw[held_block] != DRAW_GAS) {
|
||||||
float height = Blocks.MaxBB[held_block].Y - Blocks.MinBB[held_block].Y;
|
float height = Blocks.MaxBB[held_block].Y - Blocks.MinBB[held_block].Y;
|
||||||
held_entity.Position.Y += 0.2f * (1.0f - height);
|
held_entity.Position.Y += 0.2f * (1.0f - height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
102
src/Http.c
102
src/Http.c
@ -124,7 +124,7 @@ static void Http_SysInit(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Adds custom HTTP headers for a req */
|
/* Adds custom HTTP headers for a req */
|
||||||
static void Http_SysMakeHeaders(String* headers, struct HttpRequest* req) {
|
static void Http_MakeHeaders(String* headers, struct HttpRequest* req) {
|
||||||
if (!req->Etag[0] && !req->LastModified && !req->Data) {
|
if (!req->Etag[0] && !req->LastModified && !req->Data) {
|
||||||
headers->buffer = NULL; return;
|
headers->buffer = NULL; return;
|
||||||
}
|
}
|
||||||
@ -150,8 +150,8 @@ static void Http_SysMakeHeaders(String* headers, struct HttpRequest* req) {
|
|||||||
headers->buffer[headers->length] = '\0';
|
headers->buffer[headers->length] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Creates and sends a http req */
|
/* Creates and sends a HTTP requst */
|
||||||
static ReturnCode Http_SysMakeRequest(struct HttpRequest* req, HINTERNET* handle) {
|
static ReturnCode Http_StartRequest(struct HttpRequest* req, HINTERNET* handle) {
|
||||||
const static char* verbs[3] = { "GET", "HEAD", "POST" };
|
const static char* verbs[3] = { "GET", "HEAD", "POST" };
|
||||||
struct HttpCacheEntry entry;
|
struct HttpCacheEntry entry;
|
||||||
DWORD flags;
|
DWORD flags;
|
||||||
@ -167,7 +167,7 @@ static ReturnCode Http_SysMakeRequest(struct HttpRequest* req, HINTERNET* handle
|
|||||||
HttpCache_Lookup(&entry);
|
HttpCache_Lookup(&entry);
|
||||||
/* https://stackoverflow.com/questions/25308488/c-wininet-custom-http-headers */
|
/* https://stackoverflow.com/questions/25308488/c-wininet-custom-http-headers */
|
||||||
String_InitArray(headers, headersBuffer);
|
String_InitArray(headers, headersBuffer);
|
||||||
Http_SysMakeHeaders(&headers, req);
|
Http_MakeHeaders(&headers, req);
|
||||||
|
|
||||||
flags = INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD;
|
flags = INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD;
|
||||||
if (entry.Https) flags |= INTERNET_FLAG_SECURE;
|
if (entry.Https) flags |= INTERNET_FLAG_SECURE;
|
||||||
@ -179,8 +179,8 @@ static ReturnCode Http_SysMakeRequest(struct HttpRequest* req, HINTERNET* handle
|
|||||||
req->Data, req->Size) ? 0 : GetLastError();
|
req->Data, req->Size) ? 0 : GetLastError();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gets headers from a http response */
|
/* Gets headers from a HTTP response */
|
||||||
static ReturnCode Http_SysGetHeaders(struct HttpRequest* req, HINTERNET handle) {
|
static ReturnCode Http_ProcessHeaders(struct HttpRequest* req, HINTERNET handle) {
|
||||||
DWORD len;
|
DWORD len;
|
||||||
|
|
||||||
len = sizeof(DWORD);
|
len = sizeof(DWORD);
|
||||||
@ -207,8 +207,8 @@ static ReturnCode Http_SysGetHeaders(struct HttpRequest* req, HINTERNET handle)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gets the data/contents of a http response */
|
/* Downloads the data/contents of a HTTP response */
|
||||||
static ReturnCode Http_SysGetData(struct HttpRequest* req, HINTERNET handle, volatile int* progress) {
|
static ReturnCode Http_DownloadData(struct HttpRequest* req, HINTERNET handle, volatile int* progress) {
|
||||||
uint8_t* buffer;
|
uint8_t* buffer;
|
||||||
uint32_t size, totalRead;
|
uint32_t size, totalRead;
|
||||||
uint32_t read, avail;
|
uint32_t read, avail;
|
||||||
@ -246,19 +246,18 @@ static ReturnCode Http_SysGetData(struct HttpRequest* req, HINTERNET handle, vol
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Performs a http req and inspecting the response */
|
|
||||||
static ReturnCode Http_SysDo(struct HttpRequest* req, volatile int* progress) {
|
static ReturnCode Http_SysDo(struct HttpRequest* req, volatile int* progress) {
|
||||||
HINTERNET handle;
|
HINTERNET handle;
|
||||||
ReturnCode res = Http_SysMakeRequest(req, &handle);
|
ReturnCode res = Http_StartRequest(req, &handle);
|
||||||
HttpRequest_Free(req);
|
HttpRequest_Free(req);
|
||||||
if (res) return res;
|
if (res) return res;
|
||||||
|
|
||||||
*progress = ASYNC_PROGRESS_FETCHING_DATA;
|
*progress = ASYNC_PROGRESS_FETCHING_DATA;
|
||||||
res = Http_SysGetHeaders(req, handle);
|
res = Http_ProcessHeaders(req, handle);
|
||||||
if (res) { InternetCloseHandle(handle); return res; }
|
if (res) { InternetCloseHandle(handle); return res; }
|
||||||
|
|
||||||
if (req->RequestType != REQUEST_TYPE_HEAD) {
|
if (req->RequestType != REQUEST_TYPE_HEAD) {
|
||||||
res = Http_SysGetData(req, handle, progress);
|
res = Http_DownloadData(req, handle, progress);
|
||||||
if (res) { InternetCloseHandle(handle); return res; }
|
if (res) { InternetCloseHandle(handle); return res; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,13 +284,15 @@ static void Http_SysInit(void) {
|
|||||||
if (!curl) Logger_Abort("Failed to init easy curl");
|
if (!curl) Logger_Abort("Failed to init easy curl");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int Http_SysProgress(int* progress, double total, double received, double a, double b) {
|
/* Updates progress of current download */
|
||||||
|
static int Http_UpdateProgress(int* progress, double total, double received, double a, double b) {
|
||||||
if (total == 0) return 0;
|
if (total == 0) return 0;
|
||||||
*progress = (int)(100 * received / total);
|
*progress = (int)(100 * received / total);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct curl_slist* Http_SysMake(struct HttpRequest* req) {
|
/* Makes custom request HTTP headers, usually none. */
|
||||||
|
static struct curl_slist* Http_MakeHeaders(struct HttpRequest* req) {
|
||||||
String tmp; char buffer[STRING_SIZE + 1];
|
String tmp; char buffer[STRING_SIZE + 1];
|
||||||
struct curl_slist* list = NULL;
|
struct curl_slist* list = NULL;
|
||||||
String etag;
|
String etag;
|
||||||
@ -317,19 +318,8 @@ static struct curl_slist* Http_SysMake(struct HttpRequest* req) {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Http_SysSetType(struct HttpRequest* req) {
|
/* Processes a HTTP header downloaded from the server */
|
||||||
if (req->RequestType == REQUEST_TYPE_HEAD) {
|
static size_t Http_ProcessHeader(char *buffer, size_t size, size_t nitems, struct HttpRequest* req) {
|
||||||
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
|
|
||||||
} else if (req->RequestType == REQUEST_TYPE_POST) {
|
|
||||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
|
||||||
/* TODO: Just use POSTFIELDS ?? */
|
|
||||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, req->Size);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, req->Data);
|
|
||||||
HttpRequest_Free(req);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t Http_SysGetHeaders(char *buffer, size_t size, size_t nitems, struct HttpRequest* req) {
|
|
||||||
String tmp; char tmpBuffer[STRING_SIZE + 1];
|
String tmp; char tmpBuffer[STRING_SIZE + 1];
|
||||||
String line, name, value;
|
String line, name, value;
|
||||||
time_t time;
|
time_t time;
|
||||||
@ -361,7 +351,8 @@ static size_t Http_SysGetHeaders(char *buffer, size_t size, size_t nitems, struc
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int curlBufferSize;
|
static int curlBufferSize;
|
||||||
static size_t Http_SysGetData(char *buffer, size_t size, size_t nitems, struct HttpRequest* req) {
|
/* Processes a chunk of data downloaded from the web server */
|
||||||
|
static size_t Http_ProcessData(char *buffer, size_t size, size_t nitems, struct HttpRequest* req) {
|
||||||
uint8_t* dst;
|
uint8_t* dst;
|
||||||
|
|
||||||
if (!curlBufferSize) {
|
if (!curlBufferSize) {
|
||||||
@ -385,32 +376,49 @@ static size_t Http_SysGetData(char *buffer, size_t size, size_t nitems, struct H
|
|||||||
return nitems;
|
return nitems;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ReturnCode Http_SysDo(struct HttpRequest* req, volatile int* progress) {
|
/* Sets general curl options for a request */
|
||||||
struct curl_slist* list;
|
static void Http_SetCurlOpts(struct HttpRequest* req, volatile int* progress) {
|
||||||
String url = String_FromRawArray(req->URL);
|
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "");
|
||||||
char urlStr[600];
|
|
||||||
long status = 0;
|
|
||||||
CURLcode res;
|
|
||||||
|
|
||||||
Platform_ConvertString(urlStr, &url);
|
|
||||||
curl_easy_reset(curl);
|
|
||||||
list = Http_SysMake(req);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "");
|
|
||||||
Http_SysSetType(req);
|
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, urlStr);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, GAME_APP_NAME);
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, GAME_APP_NAME);
|
||||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
|
||||||
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, Http_SysProgress);
|
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, Http_UpdateProgress);
|
||||||
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, progress);
|
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, progress);
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, Http_SysGetHeaders);
|
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, Http_ProcessHeader);
|
||||||
curl_easy_setopt(curl, CURLOPT_HEADERDATA, req);
|
curl_easy_setopt(curl, CURLOPT_HEADERDATA, req);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Http_SysGetData);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Http_ProcessData);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, req);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ReturnCode Http_SysDo(struct HttpRequest* req, volatile int* progress) {
|
||||||
|
String url = String_FromRawArray(req->URL);
|
||||||
|
char urlStr[600];
|
||||||
|
void* post_data = req->Data;
|
||||||
|
struct curl_slist* list;
|
||||||
|
long status = 0;
|
||||||
|
CURLcode res;
|
||||||
|
|
||||||
|
curl_easy_reset(curl);
|
||||||
|
list = Http_MakeHeaders(req);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
|
||||||
|
|
||||||
|
Http_SetCurlOpts(req, progress);
|
||||||
|
Platform_ConvertString(urlStr, &url);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, urlStr);
|
||||||
|
|
||||||
|
if (req->RequestType == REQUEST_TYPE_HEAD) {
|
||||||
|
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
|
||||||
|
} else if (req->RequestType == REQUEST_TYPE_POST) {
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, req->Size);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, req->Data);
|
||||||
|
|
||||||
|
/* per curl docs, we must persist POST data until request finishes */
|
||||||
|
req->Data = NULL;
|
||||||
|
HttpRequest_Free(req);
|
||||||
|
}
|
||||||
|
|
||||||
curlBufferSize = 0;
|
curlBufferSize = 0;
|
||||||
*progress = ASYNC_PROGRESS_FETCHING_DATA;
|
*progress = ASYNC_PROGRESS_FETCHING_DATA;
|
||||||
@ -421,6 +429,8 @@ static ReturnCode Http_SysDo(struct HttpRequest* req, volatile int* progress) {
|
|||||||
req->StatusCode = status;
|
req->StatusCode = status;
|
||||||
|
|
||||||
curl_slist_free_all(list);
|
curl_slist_free_all(list);
|
||||||
|
/* can free now that request has finished */
|
||||||
|
Mem_Free(post_data);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -714,7 +714,7 @@ static int LTable_GetSelectedIndex(struct LTable* w) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sets selected row to given row, scrolling table if needed. */
|
/* Sets selected row to given row, scrolling table if needed */
|
||||||
static void LTable_SetSelectedTo(struct LTable* w, int index) {
|
static void LTable_SetSelectedTo(struct LTable* w, int index) {
|
||||||
if (!w->RowsCount) return;
|
if (!w->RowsCount) return;
|
||||||
if (index >= w->RowsCount) index = w->RowsCount - 1;
|
if (index >= w->RowsCount) index = w->RowsCount - 1;
|
||||||
@ -834,7 +834,6 @@ static void LTable_DrawHeaders(struct LTable* w) {
|
|||||||
|
|
||||||
/* Draws contents of the currently visible rows in the table */
|
/* Draws contents of the currently visible rows in the table */
|
||||||
static void LTable_DrawRows(struct LTable* w) {
|
static void LTable_DrawRows(struct LTable* w) {
|
||||||
BitmapCol gridCol = BITMAPCOL_CONST(20, 20, 10, 255);
|
|
||||||
String str; char strBuffer[STRING_SIZE];
|
String str; char strBuffer[STRING_SIZE];
|
||||||
struct ServerInfo* entry;
|
struct ServerInfo* entry;
|
||||||
struct DrawTextArgs args;
|
struct DrawTextArgs args;
|
||||||
|
@ -878,7 +878,7 @@ static bool FontData_Init(const String* path, struct FontData* data, FT_Open_Arg
|
|||||||
/* For OSX font suitcase files */
|
/* For OSX font suitcase files */
|
||||||
#ifdef CC_BUILD_OSX
|
#ifdef CC_BUILD_OSX
|
||||||
String filename = String_NT_Array(data->filename);
|
String filename = String_NT_Array(data->filename);
|
||||||
String_Copy(&filename, &path);
|
String_Copy(&filename, path);
|
||||||
data->filename[filename.length] = '\0';
|
data->filename[filename.length] = '\0';
|
||||||
args->pathname = data->filename;
|
args->pathname = data->filename;
|
||||||
#endif
|
#endif
|
||||||
|
59
src/Window.c
59
src/Window.c
@ -1985,6 +1985,10 @@ OSStatus Window_ProcessMouseEvent(EventHandlerCallRef inCaller, EventRef inEvent
|
|||||||
if (win_state != WINDOW_STATE_FULLSCREEN) {
|
if (win_state != WINDOW_STATE_FULLSCREEN) {
|
||||||
mousePos.Y -= title_height;
|
mousePos.Y -= title_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* mousePos.Y will be < 0 if user clicks or moves on titlebar */
|
||||||
|
/* don't intercept this, prevents clicking close/minimise/maximise from working */
|
||||||
|
if (mousePos.Y < 0) return eventNotHandledErr;
|
||||||
|
|
||||||
kind = GetEventKind(inEvent);
|
kind = GetEventKind(inEvent);
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
@ -2078,10 +2082,7 @@ static void Window_ConnectEvents(void) {
|
|||||||
EventTargetRef target;
|
EventTargetRef target;
|
||||||
OSStatus res;
|
OSStatus res;
|
||||||
|
|
||||||
target = GetApplicationEventTarget();
|
target = GetWindowEventTarget(win_handle);
|
||||||
/* TODO: Use EventTargetRef target = GetWindowEventTarget(windowRef); instead?? */
|
|
||||||
/* need WindowEventTargetRef, otherwise message boxes don't work */
|
|
||||||
/* but if use WindowEventTargetRef, can't click quit/move buttons anymore */
|
|
||||||
res = InstallEventHandler(target, NewEventHandlerUPP(Window_EventHandler),
|
res = InstallEventHandler(target, NewEventHandlerUPP(Window_EventHandler),
|
||||||
Array_Elems(eventTypes), eventTypes, NULL, NULL);
|
Array_Elems(eventTypes), eventTypes, NULL, NULL);
|
||||||
if (res) Logger_Abort2(res, "Connecting events");
|
if (res) Logger_Abort2(res, "Connecting events");
|
||||||
@ -2345,6 +2346,8 @@ void Window_ShowDialog(const char* title, const char* msg) {
|
|||||||
RunStandardAlert(dialog, NULL, &itemHit);
|
RunStandardAlert(dialog, NULL, &itemHit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO: WORK OUT WHY THIS IS BROKEN!!!!
|
||||||
static CGrafPtr win_winPort;
|
static CGrafPtr win_winPort;
|
||||||
static CGImageRef win_image;
|
static CGImageRef win_image;
|
||||||
|
|
||||||
@ -2375,7 +2378,7 @@ void Window_DrawRaw(Rect2D r) {
|
|||||||
err = QDBeginCGContext(win_winPort, &context);
|
err = QDBeginCGContext(win_winPort, &context);
|
||||||
if (err) Logger_Abort2(err, "Begin draw");
|
if (err) Logger_Abort2(err, "Begin draw");
|
||||||
|
|
||||||
/* TODO: Only update changed bit.. */
|
// TODO: Only update changed bit..
|
||||||
rect.origin.x = 0; rect.origin.y = 0;
|
rect.origin.x = 0; rect.origin.y = 0;
|
||||||
rect.size.width = Window_ClientSize.Width;
|
rect.size.width = Window_ClientSize.Width;
|
||||||
rect.size.height = Window_ClientSize.Height;
|
rect.size.height = Window_ClientSize.Height;
|
||||||
@ -2385,6 +2388,52 @@ void Window_DrawRaw(Rect2D r) {
|
|||||||
err = QDEndCGContext(win_winPort, &context);
|
err = QDEndCGContext(win_winPort, &context);
|
||||||
if (err) Logger_Abort2(err, "End draw");
|
if (err) Logger_Abort2(err, "End draw");
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static CGrafPtr win_winPort;
|
||||||
|
static CGImageRef win_image;
|
||||||
|
static Bitmap* bmp_;
|
||||||
|
static CGColorSpaceRef colorSpace;
|
||||||
|
static CGDataProviderRef provider;
|
||||||
|
|
||||||
|
void Window_InitRaw(Bitmap* bmp) {
|
||||||
|
if (!win_winPort) win_winPort = GetWindowPort(win_handle);
|
||||||
|
Mem_Free(bmp->Scan0);
|
||||||
|
bmp->Scan0 = Mem_Alloc(bmp->Width * bmp->Height, 4, "window pixels");
|
||||||
|
|
||||||
|
colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||||
|
|
||||||
|
bmp_ = bmp;
|
||||||
|
//CGColorSpaceRelease(colorSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window_DrawRaw(Rect2D r) {
|
||||||
|
CGContextRef context = NULL;
|
||||||
|
CGRect rect;
|
||||||
|
OSStatus err;
|
||||||
|
|
||||||
|
err = QDBeginCGContext(win_winPort, &context);
|
||||||
|
if (err) Logger_Abort2(err, "Begin draw");
|
||||||
|
/* TODO: REPLACE THIS AWFUL HACK */
|
||||||
|
|
||||||
|
/* TODO: Only update changed bit.. */
|
||||||
|
rect.origin.x = 0; rect.origin.y = 0;
|
||||||
|
rect.size.width = Window_ClientSize.Width;
|
||||||
|
rect.size.height = Window_ClientSize.Height;
|
||||||
|
|
||||||
|
provider = CGDataProviderCreateWithData(NULL, bmp_->Scan0,
|
||||||
|
Bitmap_DataSize(bmp_->Width, bmp_->Height), NULL);
|
||||||
|
win_image = CGImageCreate(bmp_->Width, bmp_->Height, 8, 32, bmp_->Width * 4, colorSpace,
|
||||||
|
kCGBitmapByteOrder32Little | kCGImageAlphaFirst, provider, NULL, 0, 0);
|
||||||
|
|
||||||
|
CGContextDrawImage(context, rect, win_image);
|
||||||
|
CGContextSynchronize(context);
|
||||||
|
err = QDEndCGContext(win_winPort, &context);
|
||||||
|
if (err) Logger_Abort2(err, "End draw");
|
||||||
|
|
||||||
|
CGImageRelease(win_image);
|
||||||
|
CGDataProviderRelease(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*########################################################################################################################*
|
/*########################################################################################################################*
|
||||||
|
@ -30,6 +30,33 @@ FT_BEGIN_HEADER
|
|||||||
/* see https://support.microsoft.com/en-us/kb/130437 */
|
/* see https://support.microsoft.com/en-us/kb/130437 */
|
||||||
#define FT_MAC_RFORK_MAX_LEN 0x00FFFFFFUL
|
#define FT_MAC_RFORK_MAX_LEN 0x00FFFFFFUL
|
||||||
|
|
||||||
|
#ifdef FT_MACINTOSH
|
||||||
|
|
||||||
|
|
||||||
|
/* Assume the stream is sfnt-wrapped PS Type1 or sfnt-wrapped CID-keyed */
|
||||||
|
/* font, and try to load a face specified by the face_index. */
|
||||||
|
FT_LOCAL(FT_Error)
|
||||||
|
open_face_PS_from_sfnt_stream(FT_Library library,
|
||||||
|
FT_Stream stream,
|
||||||
|
FT_Long face_index,
|
||||||
|
FT_Int num_params,
|
||||||
|
FT_Parameter *params,
|
||||||
|
FT_Face *aface);
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a new FT_Face given a buffer and a driver name. */
|
||||||
|
/* From ftmac.c. */
|
||||||
|
FT_LOCAL(FT_Error)
|
||||||
|
open_face_from_buffer(FT_Library library,
|
||||||
|
FT_Byte* base,
|
||||||
|
FT_ULong size,
|
||||||
|
FT_Long face_index,
|
||||||
|
const char* driver_name,
|
||||||
|
FT_Face *aface);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
FT_END_HEADER
|
FT_END_HEADER
|
||||||
|
|
||||||
#endif /* FTBASE_H_ */
|
#endif /* FTBASE_H_ */
|
||||||
|
@ -1382,6 +1382,301 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef FT_MACINTOSH
|
||||||
|
|
||||||
|
/* The behavior here is very similar to that in base/ftmac.c, but it */
|
||||||
|
/* is designed to work on non-mac systems, so no mac specific calls. */
|
||||||
|
/* */
|
||||||
|
/* We look at the file and determine if it is a mac dfont file or a mac */
|
||||||
|
/* resource file, or a macbinary file containing a mac resource file. */
|
||||||
|
/* */
|
||||||
|
/* Unlike ftmac I'm not going to look at a `FOND'. I don't really see */
|
||||||
|
/* the point, especially since there may be multiple `FOND' resources. */
|
||||||
|
/* Instead I'll just look for `sfnt' and `POST' resources, ordered as */
|
||||||
|
/* they occur in the file. */
|
||||||
|
/* */
|
||||||
|
/* Note that multiple `POST' resources do not mean multiple postscript */
|
||||||
|
/* fonts; they all get jammed together to make what is essentially a */
|
||||||
|
/* pfb file. */
|
||||||
|
/* */
|
||||||
|
/* We aren't interested in `NFNT' or `FONT' bitmap resources. */
|
||||||
|
/* */
|
||||||
|
/* As soon as we get an `sfnt' load it into memory and pass it off to */
|
||||||
|
/* FT_Open_Face. */
|
||||||
|
/* */
|
||||||
|
/* If we have a (set of) `POST' resources, massage them into a (memory) */
|
||||||
|
/* pfb file and pass that to FT_Open_Face. (As with ftmac.c I'm not */
|
||||||
|
/* going to try to save the kerning info. After all that lives in the */
|
||||||
|
/* `FOND' which isn't in the file containing the `POST' resources so */
|
||||||
|
/* we don't really have access to it. */
|
||||||
|
|
||||||
|
|
||||||
|
/* Finalizer for a memory stream; gets called by FT_Done_Face(). */
|
||||||
|
/* It frees the memory it uses. */
|
||||||
|
/* From `ftmac.c'. */
|
||||||
|
static void
|
||||||
|
memory_stream_close( FT_Stream stream )
|
||||||
|
{
|
||||||
|
FT_Memory memory = stream->memory;
|
||||||
|
|
||||||
|
|
||||||
|
FT_FREE( stream->base );
|
||||||
|
|
||||||
|
stream->size = 0;
|
||||||
|
stream->base = NULL;
|
||||||
|
stream->close = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a new memory stream from a buffer and a size. */
|
||||||
|
/* From `ftmac.c'. */
|
||||||
|
static FT_Error
|
||||||
|
new_memory_stream( FT_Library library,
|
||||||
|
FT_Byte* base,
|
||||||
|
FT_ULong size,
|
||||||
|
FT_Stream_CloseFunc close,
|
||||||
|
FT_Stream *astream )
|
||||||
|
{
|
||||||
|
FT_Error error;
|
||||||
|
FT_Memory memory;
|
||||||
|
FT_Stream stream = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
if ( !library )
|
||||||
|
return FT_THROW( Invalid_Library_Handle );
|
||||||
|
|
||||||
|
if ( !base )
|
||||||
|
return FT_THROW( Invalid_Argument );
|
||||||
|
|
||||||
|
*astream = NULL;
|
||||||
|
memory = library->memory;
|
||||||
|
if ( FT_NEW( stream ) )
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
FT_Stream_OpenMemory( stream, base, size );
|
||||||
|
|
||||||
|
stream->close = close;
|
||||||
|
|
||||||
|
*astream = stream;
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a new FT_Face given a buffer and a driver name. */
|
||||||
|
/* From `ftmac.c'. */
|
||||||
|
FT_LOCAL_DEF( FT_Error )
|
||||||
|
open_face_from_buffer( FT_Library library,
|
||||||
|
FT_Byte* base,
|
||||||
|
FT_ULong size,
|
||||||
|
FT_Long face_index,
|
||||||
|
const char* driver_name,
|
||||||
|
FT_Face *aface )
|
||||||
|
{
|
||||||
|
FT_Open_Args args;
|
||||||
|
FT_Error error;
|
||||||
|
FT_Stream stream = NULL;
|
||||||
|
FT_Memory memory = library->memory;
|
||||||
|
|
||||||
|
|
||||||
|
error = new_memory_stream( library,
|
||||||
|
base,
|
||||||
|
size,
|
||||||
|
memory_stream_close,
|
||||||
|
&stream );
|
||||||
|
if ( error )
|
||||||
|
{
|
||||||
|
FT_FREE( base );
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.flags = FT_OPEN_STREAM;
|
||||||
|
args.stream = stream;
|
||||||
|
if ( driver_name )
|
||||||
|
{
|
||||||
|
args.flags = args.flags | FT_OPEN_DRIVER;
|
||||||
|
args.driver = FT_Get_Module( library, driver_name );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point, the face index has served its purpose; */
|
||||||
|
/* whoever calls this function has already used it to */
|
||||||
|
/* locate the correct font data. We should not propagate */
|
||||||
|
/* this index to FT_Open_Face() (unless it is negative). */
|
||||||
|
|
||||||
|
if ( face_index > 0 )
|
||||||
|
face_index &= 0x7FFF0000L; /* retain GX data */
|
||||||
|
|
||||||
|
error = ft_open_face_internal( library, &args, face_index, aface, 0 );
|
||||||
|
|
||||||
|
if ( !error )
|
||||||
|
(*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
|
||||||
|
else
|
||||||
|
FT_Stream_Free( stream, 0 );
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Look up `TYP1' or `CID ' table from sfnt table directory. */
|
||||||
|
/* `offset' and `length' must exclude the binary header in tables. */
|
||||||
|
|
||||||
|
/* Type 1 and CID-keyed font drivers should recognize sfnt-wrapped */
|
||||||
|
/* format too. Here, since we can't expect that the TrueType font */
|
||||||
|
/* driver is loaded unconditionally, we must parse the font by */
|
||||||
|
/* ourselves. We are only interested in the name of the table and */
|
||||||
|
/* the offset. */
|
||||||
|
|
||||||
|
static FT_Error
|
||||||
|
ft_lookup_PS_in_sfnt_stream( FT_Stream stream,
|
||||||
|
FT_Long face_index,
|
||||||
|
FT_ULong* offset,
|
||||||
|
FT_ULong* length,
|
||||||
|
FT_Bool* is_sfnt_cid )
|
||||||
|
{
|
||||||
|
FT_Error error;
|
||||||
|
FT_UShort numTables;
|
||||||
|
FT_Long pstable_index;
|
||||||
|
FT_ULong tag;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
|
||||||
|
*offset = 0;
|
||||||
|
*length = 0;
|
||||||
|
*is_sfnt_cid = FALSE;
|
||||||
|
|
||||||
|
/* TODO: support for sfnt-wrapped PS/CID in TTC format */
|
||||||
|
|
||||||
|
/* version check for 'typ1' (should be ignored?) */
|
||||||
|
if ( FT_READ_ULONG( tag ) )
|
||||||
|
return error;
|
||||||
|
if ( tag != TTAG_typ1 )
|
||||||
|
return FT_THROW( Unknown_File_Format );
|
||||||
|
|
||||||
|
if ( FT_READ_USHORT( numTables ) )
|
||||||
|
return error;
|
||||||
|
if ( FT_STREAM_SKIP( 2 * 3 ) ) /* skip binary search header */
|
||||||
|
return error;
|
||||||
|
|
||||||
|
pstable_index = -1;
|
||||||
|
*is_sfnt_cid = FALSE;
|
||||||
|
|
||||||
|
for ( i = 0; i < numTables; i++ )
|
||||||
|
{
|
||||||
|
if ( FT_READ_ULONG( tag ) || FT_STREAM_SKIP( 4 ) ||
|
||||||
|
FT_READ_ULONG( *offset ) || FT_READ_ULONG( *length ) )
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if ( tag == TTAG_CID )
|
||||||
|
{
|
||||||
|
pstable_index++;
|
||||||
|
*offset += 22;
|
||||||
|
*length -= 22;
|
||||||
|
*is_sfnt_cid = TRUE;
|
||||||
|
if ( face_index < 0 )
|
||||||
|
return FT_Err_Ok;
|
||||||
|
}
|
||||||
|
else if ( tag == TTAG_TYP1 )
|
||||||
|
{
|
||||||
|
pstable_index++;
|
||||||
|
*offset += 24;
|
||||||
|
*length -= 24;
|
||||||
|
*is_sfnt_cid = FALSE;
|
||||||
|
if ( face_index < 0 )
|
||||||
|
return FT_Err_Ok;
|
||||||
|
}
|
||||||
|
if ( face_index >= 0 && pstable_index == face_index )
|
||||||
|
return FT_Err_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FT_THROW( Table_Missing );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FT_LOCAL_DEF( FT_Error )
|
||||||
|
open_face_PS_from_sfnt_stream( FT_Library library,
|
||||||
|
FT_Stream stream,
|
||||||
|
FT_Long face_index,
|
||||||
|
FT_Int num_params,
|
||||||
|
FT_Parameter *params,
|
||||||
|
FT_Face *aface )
|
||||||
|
{
|
||||||
|
FT_Error error;
|
||||||
|
FT_Memory memory = library->memory;
|
||||||
|
FT_ULong offset, length;
|
||||||
|
FT_ULong pos;
|
||||||
|
FT_Bool is_sfnt_cid;
|
||||||
|
FT_Byte* sfnt_ps = NULL;
|
||||||
|
|
||||||
|
FT_UNUSED( num_params );
|
||||||
|
FT_UNUSED( params );
|
||||||
|
|
||||||
|
|
||||||
|
/* ignore GX stuff */
|
||||||
|
if ( face_index > 0 )
|
||||||
|
face_index &= 0xFFFFL;
|
||||||
|
|
||||||
|
pos = FT_STREAM_POS();
|
||||||
|
|
||||||
|
error = ft_lookup_PS_in_sfnt_stream( stream,
|
||||||
|
face_index,
|
||||||
|
&offset,
|
||||||
|
&length,
|
||||||
|
&is_sfnt_cid );
|
||||||
|
if ( error )
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
if ( offset > stream->size )
|
||||||
|
{
|
||||||
|
FT_TRACE2(( "open_face_PS_from_sfnt_stream: invalid table offset\n" ));
|
||||||
|
error = FT_THROW( Invalid_Table );
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
else if ( length > stream->size - offset )
|
||||||
|
{
|
||||||
|
FT_TRACE2(( "open_face_PS_from_sfnt_stream: invalid table length\n" ));
|
||||||
|
error = FT_THROW( Invalid_Table );
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = FT_Stream_Seek( stream, pos + offset );
|
||||||
|
if ( error )
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
if ( FT_ALLOC( sfnt_ps, (FT_Long)length ) )
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
error = FT_Stream_Read( stream, (FT_Byte *)sfnt_ps, length );
|
||||||
|
if ( error )
|
||||||
|
{
|
||||||
|
FT_FREE( sfnt_ps );
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = open_face_from_buffer( library,
|
||||||
|
sfnt_ps,
|
||||||
|
length,
|
||||||
|
FT_MIN( face_index, 0 ),
|
||||||
|
is_sfnt_cid ? "cid" : "type1",
|
||||||
|
aface );
|
||||||
|
Exit:
|
||||||
|
{
|
||||||
|
FT_Error error1;
|
||||||
|
|
||||||
|
|
||||||
|
if ( FT_ERR_EQ( error, Unknown_File_Format ) )
|
||||||
|
{
|
||||||
|
error1 = FT_Stream_Seek( stream, pos );
|
||||||
|
if ( error1 )
|
||||||
|
return error1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* FT_MACINTOSH */
|
||||||
|
|
||||||
|
|
||||||
/* documentation is in freetype.h */
|
/* documentation is in freetype.h */
|
||||||
|
|
||||||
#ifndef FT_MACINTOSH
|
#ifndef FT_MACINTOSH
|
||||||
|
Loading…
x
Reference in New Issue
Block a user