mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-11-26 10:49:21 +00:00
More clipboard-related fixes for Basilisk / SheepShaver
This patch fixes one lingering problem with the 64-bit clipboard code; the way it was designed, the Mac clipboard was being cleared every time a single item was being requested by GetScrap, causing clipboards with multiple items to be unceremoniously whittled down to one. On the other hand, a similar issue was causing some items to get duplicated on the host pasteboard. This patch fixes the issue by making conversion between the host pasteboard and the Mac clipboard a singular operation; when the pasteboard data changes on the host side, it is all converted and sent to the Mac pasteboard at once, and similarly, all Mac clipboard data is sent to the host pasteboard in one operation. Also, data from the host side is copied to the Mac clipboard only if it has changed since the last check, which should improve performance as conversions will not be done over and over every time the Mac side checks whether the scrap has changed. In addition, I've added a rudimentary PICT converter. It's rudimentary at the moment, only going in one direction, converting to PICT and not from PICT, and currently it always rasterizes the source image and creates a PICT containing bitmap data. However, it's a start, and it should solve Ronald's issue with copying images from OS X to Mac OS. In the future, more could possibly be added. I've put the new PICT code in the main source directory instead of in the MacOSX subdirectory, so that it can be used by other platforms if needed. I would like to leave the license on the new PICT code as "Public Domain" if that is okay. Thanks, Charles
This commit is contained in:
parent
e1d132083b
commit
6f2635ee31
@ -30,6 +30,7 @@
|
||||
#include "cpu_emulation.h"
|
||||
#include "emul_op.h"
|
||||
#include "autorelease.h"
|
||||
#include "pict.h"
|
||||
|
||||
#define DEBUG 0
|
||||
#include "debug.h"
|
||||
@ -43,13 +44,14 @@
|
||||
#define TYPE_STYL FOURCC('s','t','y','l')
|
||||
|
||||
static NSPasteboard *g_pboard;
|
||||
static NSUInteger g_pb_change_count = 0;
|
||||
|
||||
// Flag for PutScrap(): the data was put by GetScrap(), don't bounce it back to the MacOS X side
|
||||
static bool we_put_this_data = false;
|
||||
|
||||
static bool should_clear = false;
|
||||
|
||||
static NSMutableDictionary *macScrap;
|
||||
static NSMutableDictionary *g_macScrap;
|
||||
|
||||
// flavor UTIs
|
||||
|
||||
@ -788,11 +790,29 @@ static NSData *ConvertToMacTEXTAndStyl(NSAttributedString *aStr, NSData **outSty
|
||||
return textData;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get data of a particular flavor from the pasteboard
|
||||
*/
|
||||
|
||||
static NSData *DataFromPasteboard(NSPasteboard *pboard, NSString *flavor)
|
||||
{
|
||||
NSArray *objs = [pboard readObjectsForClasses:[NSArray arrayWithObject:[NSPasteboardItem class]] options:nil];
|
||||
|
||||
for (NSPasteboardItem *eachItem in objs) {
|
||||
NSData *data = [eachItem dataForType:flavor];
|
||||
|
||||
if ([data length])
|
||||
return data;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert Mac TEXT/styl to RTF
|
||||
*/
|
||||
|
||||
static void WriteMacTEXTAndStylToPasteboard(NSData *textData, NSData *stylData)
|
||||
static void WriteMacTEXTAndStylToPasteboard(NSPasteboard *pboard, NSData *textData, NSData *stylData)
|
||||
{
|
||||
NSMutableAttributedString *aStr = [AttributedStringFromMacTEXTAndStyl(textData, stylData) mutableCopy];
|
||||
|
||||
@ -810,23 +830,23 @@ static void WriteMacTEXTAndStylToPasteboard(NSData *textData, NSData *stylData)
|
||||
// fix line endings
|
||||
[[aStr mutableString] replaceOccurrencesOfString:@"\r" withString:@"\n" options:NSLiteralSearch range:NSMakeRange(0, [aStr length])];
|
||||
|
||||
[g_pboard writeObjects:[NSArray arrayWithObject:aStr]];
|
||||
[pboard writeObjects:[NSArray arrayWithObject:aStr]];
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert RTF to Mac TEXT/styl
|
||||
*/
|
||||
|
||||
static NSData *GetMacTEXTAndStylDataFromPasteboard(NSData **outStylData)
|
||||
static NSData *MacTEXTAndStylDataFromPasteboard(NSPasteboard *pboard, NSData **outStylData)
|
||||
{
|
||||
NSMutableAttributedString *aStr;
|
||||
|
||||
NSArray *objs = [g_pboard readObjectsForClasses:[NSArray arrayWithObject:[NSAttributedString class]] options:nil];
|
||||
NSArray *objs = [pboard readObjectsForClasses:[NSArray arrayWithObject:[NSAttributedString class]] options:nil];
|
||||
|
||||
if ([objs count]) {
|
||||
aStr = [[objs objectAtIndex:0] mutableCopy];
|
||||
} else {
|
||||
objs = [g_pboard readObjectsForClasses:[NSArray arrayWithObject:[NSString class]] options:nil];
|
||||
objs = [pboard readObjectsForClasses:[NSArray arrayWithObject:[NSString class]] options:nil];
|
||||
|
||||
if (![objs count])
|
||||
return nil;
|
||||
@ -859,7 +879,7 @@ void ClipInit(void)
|
||||
D(bug("could not create Pasteboard\n"));
|
||||
}
|
||||
|
||||
macScrap = [[NSMutableDictionary alloc] init];
|
||||
g_macScrap = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
|
||||
|
||||
@ -872,8 +892,101 @@ void ClipExit(void)
|
||||
[g_pboard release];
|
||||
g_pboard = nil;
|
||||
|
||||
[macScrap release];
|
||||
macScrap = nil;
|
||||
[g_macScrap release];
|
||||
g_macScrap = nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an NSImage to PICT format.
|
||||
*/
|
||||
|
||||
static NSData *ConvertImageToPICT(NSImage *image) {
|
||||
if ([[image representations] count] == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSImageRep *rep = [[image representations] objectAtIndex:0];
|
||||
NSUInteger width;
|
||||
NSUInteger height;
|
||||
|
||||
if ([rep isKindOfClass:[NSBitmapImageRep class]]) {
|
||||
width = [rep pixelsWide];
|
||||
height = [rep pixelsHigh];
|
||||
} else {
|
||||
width = lrint([image size].width);
|
||||
height = lrint([image size].height);
|
||||
}
|
||||
|
||||
// create a new bitmap image rep in our desired format, following the advice here:
|
||||
// https://developer.apple.com/library/mac/#releasenotes/Cocoa/AppKitOlderNotes.html#X10_6Notes
|
||||
|
||||
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:width
|
||||
pixelsHigh:height
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:4
|
||||
hasAlpha:YES
|
||||
isPlanar:NO
|
||||
colorSpaceName:NSCalibratedRGBColorSpace
|
||||
bytesPerRow:width * 4
|
||||
bitsPerPixel:32];
|
||||
|
||||
[NSGraphicsContext saveGraphicsState];
|
||||
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:bitmap]];
|
||||
[rep draw];
|
||||
[NSGraphicsContext restoreGraphicsState];
|
||||
|
||||
unsigned char *rgba = [bitmap bitmapData];
|
||||
|
||||
long bufSize = ConvertRGBAToPICT(NULL, 0, rgba, width, height);
|
||||
|
||||
NSData *pictData = nil;
|
||||
|
||||
if (bufSize > 0) {
|
||||
uint8_t *buf = (uint8_t *)malloc(bufSize);
|
||||
|
||||
long pictSize = ConvertRGBAToPICT(buf, bufSize, rgba, width, height);
|
||||
|
||||
if (pictSize > 0)
|
||||
pictData = [NSData dataWithBytes:buf length:pictSize];
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
[bitmap release];
|
||||
|
||||
return pictData;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert any images that may be on the clipboard to PICT format if possible.
|
||||
*/
|
||||
|
||||
static NSData *MacPICTDataFromPasteboard(NSPasteboard *pboard)
|
||||
{
|
||||
// check if there's any PICT data on the pasteboard
|
||||
NSData *pictData = DataFromPasteboard(pboard, (NSString *)kUTTypePICT);
|
||||
|
||||
if (pictData)
|
||||
return pictData;
|
||||
|
||||
// now check to see if any images on the pasteboard have PICT representations
|
||||
NSArray *objs = [pboard readObjectsForClasses:[NSArray arrayWithObject:[NSImage class]] options:nil];
|
||||
|
||||
for (NSImage *eachImage in objs) {
|
||||
for (NSImageRep *eachRep in [eachImage representations]) {
|
||||
|
||||
if ([eachRep isKindOfClass:[NSPICTImageRep class]])
|
||||
return [(NSPICTImageRep *)eachRep PICTRepresentation];
|
||||
}
|
||||
}
|
||||
|
||||
// Give up and perform the conversion ourselves
|
||||
if ([objs count])
|
||||
return ConvertImageToPICT([objs objectAtIndex:0]);
|
||||
|
||||
// If none of that worked, sorry, we're out of options
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -948,6 +1061,8 @@ static void WriteDataToMacClipboard(NSData *pbData, uint32_t type)
|
||||
|
||||
r.a[0] = proc_area;
|
||||
Execute68kTrap(0xa01f, &r); // DisposePtr
|
||||
|
||||
[g_macScrap setObject:pbData forKey:[NSNumber numberWithInteger:type]];
|
||||
}
|
||||
|
||||
r.a[0] = scrap_area;
|
||||
@ -955,6 +1070,80 @@ static void WriteDataToMacClipboard(NSData *pbData, uint32_t type)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Take all the data on host pasteboard and convert it to something the Mac understands if possible
|
||||
*/
|
||||
|
||||
static void ConvertHostPasteboardToMacScrap()
|
||||
{
|
||||
ZeroMacClipboard();
|
||||
|
||||
NSData *stylData = nil;
|
||||
NSData *textData = MacTEXTAndStylDataFromPasteboard(g_pboard, &stylData);
|
||||
|
||||
if (textData) {
|
||||
if (stylData)
|
||||
WriteDataToMacClipboard(stylData, TYPE_STYL);
|
||||
|
||||
WriteDataToMacClipboard(textData, TYPE_TEXT);
|
||||
}
|
||||
|
||||
NSData *pictData = MacPICTDataFromPasteboard(g_pboard);
|
||||
|
||||
if (pictData)
|
||||
WriteDataToMacClipboard(pictData, TYPE_PICT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Take all the data on the Mac clipbord and convert it to something the host pasteboard understands if possible
|
||||
*/
|
||||
|
||||
static void ConvertMacScrapToHostPasteboard()
|
||||
{
|
||||
BOOL wroteText = NO;
|
||||
|
||||
[g_pboard clearContents];
|
||||
|
||||
for (NSNumber *eachTypeNum in g_macScrap) AUTORELEASE_POOL {
|
||||
uint32_t eachType = [eachTypeNum integerValue];
|
||||
|
||||
if (eachType == TYPE_TEXT || eachType == TYPE_STYL) {
|
||||
if(wroteText)
|
||||
continue;
|
||||
|
||||
NSData *textData;
|
||||
NSData *stylData;
|
||||
|
||||
textData = [g_macScrap objectForKey:[NSNumber numberWithInteger:TYPE_TEXT]];
|
||||
stylData = [g_macScrap objectForKey:[NSNumber numberWithInteger:TYPE_STYL]];
|
||||
|
||||
if (textData) {
|
||||
WriteMacTEXTAndStylToPasteboard(g_pboard, textData, stylData);
|
||||
wroteText = YES;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
NSData *pbData = [g_macScrap objectForKey:eachTypeNum];
|
||||
|
||||
if (pbData) {
|
||||
NSString *typeStr = GetUTIFromFlavor(eachType);
|
||||
|
||||
if(!typeStr)
|
||||
continue;
|
||||
|
||||
NSPasteboardItem *pbItem = [[NSPasteboardItem alloc] init];
|
||||
|
||||
[pbItem setData:pbData forType:typeStr];
|
||||
|
||||
[g_pboard writeObjects:[NSArray arrayWithObject:pbItem]];
|
||||
|
||||
[pbItem release];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Mac application reads clipboard
|
||||
*/
|
||||
@ -964,46 +1153,12 @@ void GetScrap(void **handle, uint32_t type, int32_t offset)
|
||||
D(bug("GetScrap handle %p, type %4.4s, offset %d\n", handle, (char *)&type, offset));
|
||||
|
||||
AUTORELEASE_POOL {
|
||||
NSString *typeStr;
|
||||
|
||||
if (!g_pboard)
|
||||
return;
|
||||
|
||||
if (!(typeStr = GetUTIFromFlavor(type)))
|
||||
return;
|
||||
|
||||
if (type == TYPE_TEXT || type == TYPE_STYL) {
|
||||
NSData *stylData = nil;
|
||||
NSData *textData = GetMacTEXTAndStylDataFromPasteboard(&stylData);
|
||||
|
||||
if (textData) {
|
||||
ZeroMacClipboard();
|
||||
|
||||
if (stylData)
|
||||
WriteDataToMacClipboard(stylData, TYPE_STYL);
|
||||
|
||||
WriteDataToMacClipboard(textData, TYPE_TEXT);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NSData *pbData = nil;
|
||||
|
||||
NSArray *objs = [g_pboard readObjectsForClasses:[NSArray arrayWithObject:[NSPasteboardItem class]] options:nil];
|
||||
|
||||
for (NSPasteboardItem *eachItem in objs) {
|
||||
NSData *data = [eachItem dataForType:typeStr];
|
||||
|
||||
if ([data length]) {
|
||||
pbData = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pbData) {
|
||||
ZeroMacClipboard();
|
||||
WriteDataToMacClipboard(pbData, type);
|
||||
if ([g_pboard changeCount] > g_pb_change_count) {
|
||||
ConvertHostPasteboardToMacScrap();
|
||||
g_pb_change_count = [g_pboard changeCount];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1032,25 +1187,19 @@ void PutScrap(uint32_t type, void *scrap, int32_t length)
|
||||
D(bug("PutScrap type %4.4s, data %p, length %ld\n", (char *)&type, scrap, (long)length));
|
||||
|
||||
AUTORELEASE_POOL {
|
||||
NSString *typeStr;
|
||||
|
||||
if (!g_pboard)
|
||||
return;
|
||||
|
||||
if (!(typeStr = GetUTIFromFlavor(type)))
|
||||
return;
|
||||
|
||||
if (we_put_this_data) {
|
||||
we_put_this_data = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (length <= 0)
|
||||
return;
|
||||
|
||||
if (should_clear) {
|
||||
[g_pboard clearContents];
|
||||
|
||||
[macScrap removeAllObjects];
|
||||
[g_macScrap removeAllObjects];
|
||||
should_clear = false;
|
||||
}
|
||||
|
||||
@ -1058,24 +1207,11 @@ void PutScrap(uint32_t type, void *scrap, int32_t length)
|
||||
if (!pbData)
|
||||
return;
|
||||
|
||||
[macScrap setObject:pbData forKey:[NSNumber numberWithInteger:type]];
|
||||
[g_macScrap setObject:pbData forKey:[NSNumber numberWithInteger:type]];
|
||||
|
||||
if (type == TYPE_TEXT || type == TYPE_STYL) {
|
||||
NSData *textData;
|
||||
NSData *stylData;
|
||||
ConvertMacScrapToHostPasteboard();
|
||||
|
||||
textData = [macScrap objectForKey:[NSNumber numberWithInteger:TYPE_TEXT]];
|
||||
stylData = [macScrap objectForKey:[NSNumber numberWithInteger:TYPE_STYL]];
|
||||
|
||||
if (textData) {
|
||||
WriteMacTEXTAndStylToPasteboard(textData, stylData);
|
||||
}
|
||||
} else if (pbData) {
|
||||
NSPasteboardItem *pbItem = [[[NSPasteboardItem alloc] init] autorelease];
|
||||
|
||||
[pbItem setData:pbData forType:typeStr];
|
||||
|
||||
[g_pboard writeObjects:[NSArray arrayWithObject:pbItem]];
|
||||
}
|
||||
// So that our PutScrap() patch won't bounce the data we just wrote back to the Mac clipboard
|
||||
g_pb_change_count = [g_pboard changeCount];
|
||||
}
|
||||
}
|
||||
|
@ -744,7 +744,7 @@ if [[ "x$WANT_SDL_VIDEO" = "xyes" ]]; then
|
||||
[AC_MSG_RESULT(yes); LP64_DEFINED=yes],
|
||||
[AC_MSG_RESULT(no)])
|
||||
if [[ "x$LP64_DEFINED" = "xyes" ]]; then
|
||||
EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx64.mm"
|
||||
EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx64.mm ../pict.c"
|
||||
else
|
||||
EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx.cpp"
|
||||
fi
|
||||
|
29
BasiliskII/src/include/pict.h
Normal file
29
BasiliskII/src/include/pict.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* pict.h - convert an image to PICT.
|
||||
*
|
||||
* Currently creates a bitmap PICT resource; vector graphics are not preserved.
|
||||
*
|
||||
* By Charles Srstka.
|
||||
*
|
||||
* Public Domain. Do with it as you wish.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ConvertRGBAToPICT
|
||||
*
|
||||
* Converts image data, in 32-bit RGBA format, to PICT.
|
||||
* Calling it first with NULL for the buffer will cause it to return a suggested buffer size.
|
||||
* Returns the number of bytes actually written, or negative if something went wrong.
|
||||
* However, this usually just means the buffer wasn't large enough.
|
||||
*/
|
||||
|
||||
ssize_t ConvertRGBAToPICT(uint8_t *buf, unsigned long bufSize, uint8_t *rgbaPixels, uint16_t width, uint16_t height);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
267
BasiliskII/src/pict.c
Normal file
267
BasiliskII/src/pict.c
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* pict.c - convert an image to PICT.
|
||||
*
|
||||
* Currently creates a bitmap PICT resource; vector graphics are not preserved.
|
||||
*
|
||||
* By Charles Srstka.
|
||||
*
|
||||
* Public Domain. Do with it as you wish.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* PICT format:
|
||||
*
|
||||
* Size: 2 bytes
|
||||
* Bounding Rect: 8 bytes
|
||||
*
|
||||
* This is followed by a series of opcodes.
|
||||
* Each opcode is 1 byte long for a Version 1 PICT, or 2 bytes long for a Version 2 PICT.
|
||||
* The ones we currently care about are:
|
||||
*
|
||||
* 0x0011 VersionOp: begins PICT version 2
|
||||
* 0x02ff Version: identifies PICT version 2
|
||||
* 0x0c00 HeaderOp: followed by 24 header bytes
|
||||
* 4 bytes: 0xFFFFFFFF for regular v2 PICT or 0xFFFE0000 for extended v2 PICT
|
||||
* 16 bytes: fixed-point bounding rectangle (or resolution, if an extended v2 PICT)
|
||||
* 4 bytes: reserved
|
||||
*
|
||||
* 0x0001 Clip: set clipping region: followed by variable-sized region
|
||||
* 0x001e DefHilite: set default highlight color
|
||||
* 0x009b DirectBitsRgn: bitmap data
|
||||
* pixMap: 50 bytes (PixMap)
|
||||
* srcRect: 8 bytes (Rect)
|
||||
* dstRect: 8 bytes (Rect)
|
||||
* mode: 2 bytes (Mode)
|
||||
* maskRgn: variable (Region)
|
||||
* pixData: variable
|
||||
* 0x00ff End of File
|
||||
*/
|
||||
|
||||
/*
|
||||
* PixMap format:
|
||||
*
|
||||
* baseAddr: Ptr (4 bytes)
|
||||
* rowBytes: Integer (2 bytes)
|
||||
* bounds: Rect (8 bytes)
|
||||
* pmVersion: Integer (2 bytes)
|
||||
* packType: Integer (2 bytes)
|
||||
* packSize: LongInt (4 bytes)
|
||||
* hRes: Fixed (4 bytes)
|
||||
* vRes: Fixed (4 bytes)
|
||||
* pixelType: Integer (2 bytes)
|
||||
* pixelSize: Integer (2 bytes)
|
||||
* cmpCount: Integer (2 bytes)
|
||||
* cmpSize: Integer (2 bytes)
|
||||
* planeBytes: LongInt (4 bytes)
|
||||
* pmTable: CTabHandle (4 bytes)
|
||||
* pmReserved: LongInt (4 bytes)
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static ssize_t CompressUsingRLE(uint8_t *row, uint16_t uncmpLength, uint8_t *outBuf, size_t bufSize)
|
||||
{
|
||||
int byteCountLength = 1 + (uncmpLength > 250);
|
||||
|
||||
uint16_t cmpCursor = byteCountLength;
|
||||
uint16_t cursor = 0;
|
||||
|
||||
// enough to output the data uncompressed if we have to, plus the length bytes
|
||||
size_t maxSize = byteCountLength + uncmpLength + (uncmpLength + 126) / 127;
|
||||
|
||||
int outOfRoom = 0;
|
||||
uint16_t cmpLength;
|
||||
|
||||
if (row == NULL || outBuf == NULL || bufSize == 0)
|
||||
return maxSize;
|
||||
|
||||
while (cursor < uncmpLength) {
|
||||
uint8_t byte = row[cursor++];
|
||||
uint8_t nextByte;
|
||||
|
||||
if (cursor < uncmpLength && (nextByte = row[cursor]) == byte) {
|
||||
int8_t matches = 1;
|
||||
|
||||
while (++cursor < uncmpLength && matches < 127 && row[cursor] == byte) {
|
||||
matches++;
|
||||
}
|
||||
|
||||
if(cmpCursor + 2 > bufSize) {
|
||||
outOfRoom = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
outBuf[cmpCursor++] = -matches;
|
||||
outBuf[cmpCursor++] = byte;
|
||||
} else {
|
||||
uint8_t literals = 0;
|
||||
uint8_t i;
|
||||
|
||||
while (cursor + literals + 1 < uncmpLength && literals < 127 && nextByte != (nextByte = row[cursor + literals + 1])) {
|
||||
literals++;
|
||||
}
|
||||
|
||||
if(cmpCursor + 2 + literals > bufSize) {
|
||||
outOfRoom = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
outBuf[cmpCursor++] = literals;
|
||||
outBuf[cmpCursor++] = byte;
|
||||
|
||||
for (i = 0; i < literals; i++) {
|
||||
outBuf[cmpCursor++] = row[cursor++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(outOfRoom) {
|
||||
// Trying to compress this just made it larger; just output the data uncompressed instead
|
||||
|
||||
if(bufSize < maxSize) {
|
||||
// sorry folks, don't have enough buffer
|
||||
return -1;
|
||||
}
|
||||
|
||||
cursor = 0;
|
||||
cmpCursor = byteCountLength;
|
||||
|
||||
while (cursor < uncmpLength) {
|
||||
uint8_t bytesToCopy = uncmpLength - cursor > 128 ? 128 : uncmpLength - cursor;
|
||||
|
||||
outBuf[cmpCursor++] = bytesToCopy - 1;
|
||||
memcpy(outBuf + cmpCursor, row + cursor, bytesToCopy); cmpCursor += bytesToCopy; cursor += bytesToCopy;
|
||||
}
|
||||
|
||||
cmpLength = cmpCursor - 1;
|
||||
}
|
||||
|
||||
cmpLength = cmpCursor - byteCountLength;
|
||||
|
||||
if (byteCountLength == 2) {
|
||||
outBuf[0] = cmpLength >> 8;
|
||||
outBuf[1] = cmpLength & 0xff;
|
||||
} else {
|
||||
outBuf[0] = cmpLength;
|
||||
}
|
||||
|
||||
return cmpCursor;
|
||||
}
|
||||
|
||||
ssize_t ConvertRGBAToPICT(uint8_t *buf, unsigned long bufSize, uint8_t *rgbaPixels, uint16_t width, uint16_t height)
|
||||
{
|
||||
unsigned long initialSize = (10 /* size + rect */ +
|
||||
6 /* initial opcodes */ +
|
||||
24 /* header */ +
|
||||
12 /* clip region */ +
|
||||
2 /* DefHilite */ +
|
||||
70 /* DirectBitsRgn - pixData - maskRgn */ +
|
||||
10 /* maskRgn */);
|
||||
|
||||
#define RECT_SIZE 8
|
||||
#define REGION_SIZE 10
|
||||
#define FIXED_RECT_SIZE 16
|
||||
|
||||
char rect[RECT_SIZE] = {0, 0, 0, 0, height >> 8, height & 0xff, width >> 8, width & 0xff };
|
||||
char region[REGION_SIZE] = { 0x00, 0x0a, rect[0], rect[1], rect[2], rect[3], rect[4], rect[5], rect[6], rect[7] };
|
||||
char fixedRect[FIXED_RECT_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, width >> 8, width & 0xff, 0, 0, height >> 8, height & 0xff, 0, 0 };
|
||||
|
||||
uint32_t hDPI = htonl(0x00480000); // 72 dpi
|
||||
uint32_t vDPI = hDPI;
|
||||
|
||||
uint16_t bytesPerPixel = 4; // RGBA
|
||||
uint16_t bytesPerRow = width * bytesPerPixel;
|
||||
|
||||
unsigned long cursor = 2; // size bytes filled in at the end
|
||||
|
||||
ssize_t cmpBufSize = CompressUsingRLE(NULL, bytesPerRow, NULL, 0);
|
||||
uint8_t cmpBuf[cmpBufSize];
|
||||
|
||||
uint16_t i;
|
||||
|
||||
if (buf == NULL || bufSize == 0) {
|
||||
// Give an upper bound for the buffer size.
|
||||
|
||||
return initialSize + height * cmpBufSize + 2;
|
||||
}
|
||||
|
||||
if (bufSize < initialSize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(buf + cursor, rect, RECT_SIZE); cursor += RECT_SIZE;
|
||||
|
||||
buf[cursor++] = 0x00; buf[cursor++] = 0x11; buf[cursor++] = 0x02; buf[cursor++] = 0xff;
|
||||
|
||||
buf[cursor++] = 0x0c; buf[cursor++] = 0x00;
|
||||
buf[cursor++] = 0xff; buf[cursor++] = 0xff; buf[cursor++] = 0xff; buf[cursor++] = 0xff;
|
||||
memcpy(buf + cursor, fixedRect, FIXED_RECT_SIZE); cursor += FIXED_RECT_SIZE;
|
||||
memset(buf + cursor, '\0', 4); cursor += 4;
|
||||
|
||||
buf[cursor++] = 0x00; buf[cursor++] = 0x1e;
|
||||
|
||||
buf[cursor++] = 0x00; buf[cursor++] = 0x01;
|
||||
memcpy(buf + cursor, region, REGION_SIZE); cursor += REGION_SIZE;
|
||||
|
||||
buf[cursor++] = 0x00; buf[cursor++] = 0x9b;
|
||||
memset(buf + cursor, '\0', 4); cursor += 4; // I think this pointer isn't used
|
||||
buf[cursor++] = (bytesPerRow >> 8) | 0x80; buf[cursor++] = bytesPerRow & 0xff; // rowBytes
|
||||
memcpy(buf + cursor, rect, RECT_SIZE); cursor += RECT_SIZE; //bounds
|
||||
buf[cursor++] = 0x00; buf[cursor++] = 0x00; // pmVersion
|
||||
buf[cursor++] = 0x00; buf[cursor++] = 0x04; // packType
|
||||
buf[cursor++] = 0x00; buf[cursor++] = 0x00; buf[cursor++] = 0x00; buf[cursor++] = 0x00; // packSize is always 0
|
||||
memcpy(buf + cursor, &hDPI, 4); cursor += 4; // hRes
|
||||
memcpy(buf + cursor, &vDPI, 4); cursor += 4; // vRes
|
||||
buf[cursor++] = 0x00; buf[cursor++] = 0x10; // pixelType; direct device
|
||||
buf[cursor++] = 0x00; buf[cursor++] = 0x20; // pixelSize; 32 bits per pixel
|
||||
buf[cursor++] = bytesPerPixel >> 8; buf[cursor++] = bytesPerPixel & 0xff; // components per pixel
|
||||
buf[cursor++] = 0x00; buf[cursor++] = 0x08; // 8 bits per component
|
||||
memset(buf + cursor, '\0', 4); cursor += 4; // planeBytes isn't used
|
||||
memset(buf + cursor, '\0', 4); cursor += 4; // don't think we need pmTable
|
||||
memset(buf + cursor, '\0', 4); cursor += 4; // reserved
|
||||
|
||||
memcpy(buf + cursor, rect, RECT_SIZE); cursor += RECT_SIZE;
|
||||
memcpy(buf + cursor, rect, RECT_SIZE); cursor += RECT_SIZE;
|
||||
buf[cursor++] = 0x00; buf[cursor++] = 0x00; // no transfer mode
|
||||
memcpy(buf + cursor, region, REGION_SIZE); cursor += REGION_SIZE;
|
||||
|
||||
for (i = 0; i < height; i++) {
|
||||
uint8_t row[bytesPerRow];
|
||||
ssize_t cmpLength;
|
||||
uint16_t j;
|
||||
|
||||
for (j = 0; j < width; j++) {
|
||||
row[j] = rgbaPixels[i * bytesPerRow + j * bytesPerPixel + 3];
|
||||
row[width + j] = rgbaPixels[i * bytesPerRow + j * bytesPerPixel];
|
||||
row[width * 2 + j] = rgbaPixels[i * bytesPerRow + j * bytesPerPixel + 1];
|
||||
row[width * 3 + j] = rgbaPixels[i * bytesPerRow + j * bytesPerPixel + 2];
|
||||
}
|
||||
|
||||
cmpLength = CompressUsingRLE(row, bytesPerRow, cmpBuf, cmpBufSize);
|
||||
|
||||
if (cmpLength < 0 || cursor + cmpLength > bufSize)
|
||||
return -1;
|
||||
|
||||
memcpy(buf + cursor, cmpBuf, cmpLength); cursor += cmpLength;
|
||||
}
|
||||
|
||||
// Fun fact: forgetting to put 0x00ff at the end of a PICT picture causes the entire
|
||||
// Classic Mac OS to crash when it tries to read it! Don't ask me how I learned this.
|
||||
if (cursor + 2 > bufSize)
|
||||
return -1;
|
||||
|
||||
buf[cursor++] = 0x00; buf[cursor++] = 0xff;
|
||||
|
||||
if(cursor > UINT16_MAX) {
|
||||
buf[0] = buf[1] = 0xff;
|
||||
} else {
|
||||
buf[0] = cursor >> 8;
|
||||
buf[1] = cursor & 0xff;
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
@ -716,7 +716,7 @@ if [[ "x$WANT_SDL_VIDEO" = "xyes" ]]; then
|
||||
[AC_MSG_RESULT(yes); LP64_DEFINED=yes],
|
||||
[AC_MSG_RESULT(no)])
|
||||
if [[ "x$LP64_DEFINED" = "xyes" ]]; then
|
||||
EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx64.mm"
|
||||
EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx64.mm ../pict.c"
|
||||
else
|
||||
EXTRASYSSRCS="$EXTRASYSSRCS ../MacOSX/clip_macosx.cpp"
|
||||
fi
|
||||
|
1
SheepShaver/src/include/pict.h
Symbolic link
1
SheepShaver/src/include/pict.h
Symbolic link
@ -0,0 +1 @@
|
||||
../../../BasiliskII/src/include/pict.h
|
1
SheepShaver/src/pict.c
Symbolic link
1
SheepShaver/src/pict.c
Symbolic link
@ -0,0 +1 @@
|
||||
../../BasiliskII/src/pict.c
|
Loading…
Reference in New Issue
Block a user