mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-18 03:55:19 -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 uint8_t bool;
|
||||
typedef uint8_t bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
#ifndef NULL
|
||||
|
@ -86,7 +86,7 @@ static void HeldBlockRenderer_SetBaseOffset(void) {
|
||||
Vector3 spriteOffset = { 0.46f, -0.52f, -0.72f };
|
||||
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) {
|
||||
float height = Blocks.MaxBB[held_block].Y - Blocks.MinBB[held_block].Y;
|
||||
held_entity.Position.Y += 0.2f * (1.0f - height);
|
||||
|
100
src/Http.c
100
src/Http.c
@ -124,7 +124,7 @@ static void Http_SysInit(void) {
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
headers->buffer = NULL; return;
|
||||
}
|
||||
@ -150,8 +150,8 @@ static void Http_SysMakeHeaders(String* headers, struct HttpRequest* req) {
|
||||
headers->buffer[headers->length] = '\0';
|
||||
}
|
||||
|
||||
/* Creates and sends a http req */
|
||||
static ReturnCode Http_SysMakeRequest(struct HttpRequest* req, HINTERNET* handle) {
|
||||
/* Creates and sends a HTTP requst */
|
||||
static ReturnCode Http_StartRequest(struct HttpRequest* req, HINTERNET* handle) {
|
||||
const static char* verbs[3] = { "GET", "HEAD", "POST" };
|
||||
struct HttpCacheEntry entry;
|
||||
DWORD flags;
|
||||
@ -167,7 +167,7 @@ static ReturnCode Http_SysMakeRequest(struct HttpRequest* req, HINTERNET* handle
|
||||
HttpCache_Lookup(&entry);
|
||||
/* https://stackoverflow.com/questions/25308488/c-wininet-custom-http-headers */
|
||||
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;
|
||||
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();
|
||||
}
|
||||
|
||||
/* Gets headers from a http response */
|
||||
static ReturnCode Http_SysGetHeaders(struct HttpRequest* req, HINTERNET handle) {
|
||||
/* Gets headers from a HTTP response */
|
||||
static ReturnCode Http_ProcessHeaders(struct HttpRequest* req, HINTERNET handle) {
|
||||
DWORD len;
|
||||
|
||||
len = sizeof(DWORD);
|
||||
@ -207,8 +207,8 @@ static ReturnCode Http_SysGetHeaders(struct HttpRequest* req, HINTERNET handle)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Gets the data/contents of a http response */
|
||||
static ReturnCode Http_SysGetData(struct HttpRequest* req, HINTERNET handle, volatile int* progress) {
|
||||
/* Downloads the data/contents of a HTTP response */
|
||||
static ReturnCode Http_DownloadData(struct HttpRequest* req, HINTERNET handle, volatile int* progress) {
|
||||
uint8_t* buffer;
|
||||
uint32_t size, totalRead;
|
||||
uint32_t read, avail;
|
||||
@ -246,19 +246,18 @@ static ReturnCode Http_SysGetData(struct HttpRequest* req, HINTERNET handle, vol
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Performs a http req and inspecting the response */
|
||||
static ReturnCode Http_SysDo(struct HttpRequest* req, volatile int* progress) {
|
||||
HINTERNET handle;
|
||||
ReturnCode res = Http_SysMakeRequest(req, &handle);
|
||||
ReturnCode res = Http_StartRequest(req, &handle);
|
||||
HttpRequest_Free(req);
|
||||
if (res) return res;
|
||||
|
||||
*progress = ASYNC_PROGRESS_FETCHING_DATA;
|
||||
res = Http_SysGetHeaders(req, handle);
|
||||
res = Http_ProcessHeaders(req, handle);
|
||||
if (res) { InternetCloseHandle(handle); return res; }
|
||||
|
||||
if (req->RequestType != REQUEST_TYPE_HEAD) {
|
||||
res = Http_SysGetData(req, handle, progress);
|
||||
res = Http_DownloadData(req, handle, progress);
|
||||
if (res) { InternetCloseHandle(handle); return res; }
|
||||
}
|
||||
|
||||
@ -285,13 +284,15 @@ static void Http_SysInit(void) {
|
||||
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;
|
||||
*progress = (int)(100 * received / total);
|
||||
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];
|
||||
struct curl_slist* list = NULL;
|
||||
String etag;
|
||||
@ -317,19 +318,8 @@ static struct curl_slist* Http_SysMake(struct HttpRequest* req) {
|
||||
return list;
|
||||
}
|
||||
|
||||
static void Http_SysSetType(struct HttpRequest* req) {
|
||||
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);
|
||||
/* 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) {
|
||||
/* Processes a HTTP header downloaded from the server */
|
||||
static size_t Http_ProcessHeader(char *buffer, size_t size, size_t nitems, struct HttpRequest* req) {
|
||||
String tmp; char tmpBuffer[STRING_SIZE + 1];
|
||||
String line, name, value;
|
||||
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 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;
|
||||
|
||||
if (!curlBufferSize) {
|
||||
@ -385,32 +376,49 @@ static size_t Http_SysGetData(char *buffer, size_t size, size_t nitems, struct H
|
||||
return nitems;
|
||||
}
|
||||
|
||||
static ReturnCode Http_SysDo(struct HttpRequest* req, volatile int* progress) {
|
||||
struct curl_slist* list;
|
||||
String url = String_FromRawArray(req->URL);
|
||||
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);
|
||||
/* Sets general curl options for a request */
|
||||
static void Http_SetCurlOpts(struct HttpRequest* req, volatile int* progress) {
|
||||
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_FOLLOWLOCATION, 1L);
|
||||
|
||||
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_HEADERFUNCTION, Http_SysGetHeaders);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, Http_ProcessHeader);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
*progress = ASYNC_PROGRESS_FETCHING_DATA;
|
||||
@ -421,6 +429,8 @@ static ReturnCode Http_SysDo(struct HttpRequest* req, volatile int* progress) {
|
||||
req->StatusCode = status;
|
||||
|
||||
curl_slist_free_all(list);
|
||||
/* can free now that request has finished */
|
||||
Mem_Free(post_data);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -714,7 +714,7 @@ static int LTable_GetSelectedIndex(struct LTable* w) {
|
||||
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) {
|
||||
if (!w->RowsCount) return;
|
||||
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 */
|
||||
static void LTable_DrawRows(struct LTable* w) {
|
||||
BitmapCol gridCol = BITMAPCOL_CONST(20, 20, 10, 255);
|
||||
String str; char strBuffer[STRING_SIZE];
|
||||
struct ServerInfo* entry;
|
||||
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 */
|
||||
#ifdef CC_BUILD_OSX
|
||||
String filename = String_NT_Array(data->filename);
|
||||
String_Copy(&filename, &path);
|
||||
String_Copy(&filename, path);
|
||||
data->filename[filename.length] = '\0';
|
||||
args->pathname = data->filename;
|
||||
#endif
|
||||
|
59
src/Window.c
59
src/Window.c
@ -1986,6 +1986,10 @@ OSStatus Window_ProcessMouseEvent(EventHandlerCallRef inCaller, EventRef inEvent
|
||||
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);
|
||||
switch (kind) {
|
||||
case kEventMouseDown:
|
||||
@ -2078,10 +2082,7 @@ static void Window_ConnectEvents(void) {
|
||||
EventTargetRef target;
|
||||
OSStatus res;
|
||||
|
||||
target = GetApplicationEventTarget();
|
||||
/* 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 */
|
||||
target = GetWindowEventTarget(win_handle);
|
||||
res = InstallEventHandler(target, NewEventHandlerUPP(Window_EventHandler),
|
||||
Array_Elems(eventTypes), eventTypes, NULL, NULL);
|
||||
if (res) Logger_Abort2(res, "Connecting events");
|
||||
@ -2345,6 +2346,8 @@ void Window_ShowDialog(const char* title, const char* msg) {
|
||||
RunStandardAlert(dialog, NULL, &itemHit);
|
||||
}
|
||||
|
||||
|
||||
/* TODO: WORK OUT WHY THIS IS BROKEN!!!!
|
||||
static CGrafPtr win_winPort;
|
||||
static CGImageRef win_image;
|
||||
|
||||
@ -2375,7 +2378,7 @@ void Window_DrawRaw(Rect2D r) {
|
||||
err = QDBeginCGContext(win_winPort, &context);
|
||||
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.size.width = Window_ClientSize.Width;
|
||||
rect.size.height = Window_ClientSize.Height;
|
||||
@ -2385,6 +2388,52 @@ void Window_DrawRaw(Rect2D r) {
|
||||
err = QDEndCGContext(win_winPort, &context);
|
||||
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 */
|
||||
#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
|
||||
|
||||
#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 */
|
||||
|
||||
#ifndef FT_MACINTOSH
|
||||
|
Loading…
x
Reference in New Issue
Block a user