mirror of
https://github.com/darlinghq/darling-cocotron.git
synced 2024-11-26 21:40:44 +00:00
1538 lines
40 KiB
Objective-C
1538 lines
40 KiB
Objective-C
/* Copyright (c) 2007 Christopher J. W. Lloyd
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
this software and associated documentation files (the "Software"), to deal in
|
|
the Software without restriction, including without limitation the rights to
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
|
|
#import <Foundation/NSArray.h>
|
|
#import <Foundation/NSBundle.h>
|
|
#import <Onyx2D/O2BitmapContext.h>
|
|
#import <Onyx2D/O2ClipPhase.h>
|
|
#import <Onyx2D/O2Color.h>
|
|
#import <Onyx2D/O2ColorSpace.h>
|
|
#import <Onyx2D/O2Context.h>
|
|
#import <Onyx2D/O2Encoding.h>
|
|
#import <Onyx2D/O2Exceptions.h>
|
|
#import <Onyx2D/O2GraphicsState.h>
|
|
#import <Onyx2D/O2Layer.h>
|
|
#import <Onyx2D/O2MutablePath.h>
|
|
#import <Onyx2D/O2PDFCharWidths.h>
|
|
#import <Onyx2D/O2PDFPage.h>
|
|
|
|
void O2ContextDefaultShowText(O2ContextRef self, const char *text,
|
|
NSUInteger length);
|
|
|
|
@implementation O2Context
|
|
|
|
- initWithBytes: (void *) bytes
|
|
width: (size_t) width
|
|
height: (size_t) height
|
|
bitsPerComponent: (size_t) bitsPerComponent
|
|
bytesPerRow: (size_t) bytesPerRow
|
|
colorSpace: (O2ColorSpaceRef) colorSpace
|
|
bitmapInfo: (O2BitmapInfo) bitmapInfo
|
|
releaseCallback: (O2BitmapContextReleaseDataCallback) releaseCallback
|
|
releaseInfo: (void *) releaseInfo
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
+ (BOOL) canInitBitmap {
|
|
return NO;
|
|
}
|
|
|
|
- initWithGraphicsState: (O2GState *) state {
|
|
_userToDeviceTransform = state->_deviceSpaceTransform;
|
|
_layerStack = [NSMutableArray new];
|
|
_stateStack = [NSMutableArray new];
|
|
[_stateStack addObject: state];
|
|
_currentState = state;
|
|
_path = [[O2MutablePath alloc] init];
|
|
_allowsAntialiasing = YES;
|
|
_textMatrix = O2AffineTransformIdentity;
|
|
_showTextFunction = O2ContextDefaultShowText;
|
|
_showGlyphsFunction = (O2ContextShowGlyphsFunction)
|
|
[self methodForSelector: @selector(showGlyphs:advances:count:)];
|
|
return self;
|
|
}
|
|
|
|
- init {
|
|
return [self initWithGraphicsState: [[[O2GState alloc] init] autorelease]];
|
|
}
|
|
|
|
- (void) dealloc {
|
|
[_layerStack release];
|
|
[_stateStack release];
|
|
[_path release];
|
|
[super dealloc];
|
|
}
|
|
|
|
- (O2Surface *) surface {
|
|
return nil;
|
|
}
|
|
|
|
- (O2Surface *) createSurfaceWithWidth: (size_t) width height: (size_t) height {
|
|
return nil;
|
|
}
|
|
|
|
- (void) beginTransparencyLayerWithInfo: (NSDictionary *) unused {
|
|
}
|
|
|
|
- (void) endTransparencyLayer {
|
|
}
|
|
|
|
O2ColorRef O2ContextStrokeColor(O2ContextRef self) {
|
|
return O2GStateStrokeColor(O2ContextCurrentGState(self));
|
|
}
|
|
|
|
O2ColorRef O2ContextFillColor(O2ContextRef self) {
|
|
return O2GStateFillColor(O2ContextCurrentGState(self));
|
|
}
|
|
|
|
- (void) setStrokeAlpha: (O2Float) alpha {
|
|
O2ColorRef color =
|
|
O2ColorCreateCopyWithAlpha(O2ContextStrokeColor(self), alpha);
|
|
O2ContextSetStrokeColorWithColor(self, color);
|
|
O2ColorRelease(color);
|
|
}
|
|
|
|
- (void) setGrayStrokeColor: (O2Float) gray {
|
|
O2Float alpha = O2ColorGetAlpha(O2ContextStrokeColor(self));
|
|
|
|
O2ContextSetGrayStrokeColor(self, gray, alpha);
|
|
}
|
|
|
|
- (void) setStrokeColorRed: (O2Float) r green: (O2Float) g blue: (O2Float) b {
|
|
O2Float alpha = O2ColorGetAlpha(O2ContextStrokeColor(self));
|
|
O2ContextSetRGBStrokeColor(self, r, g, b, alpha);
|
|
}
|
|
|
|
- (void) setStrokeColorC: (O2Float) c
|
|
m: (O2Float) m
|
|
y: (O2Float) y
|
|
k: (O2Float) k
|
|
{
|
|
O2Float alpha = O2ColorGetAlpha(O2ContextStrokeColor(self));
|
|
O2ContextSetCMYKStrokeColor(self, c, m, y, k, alpha);
|
|
}
|
|
|
|
- (void) setFillAlpha: (O2Float) alpha {
|
|
O2ColorRef color =
|
|
O2ColorCreateCopyWithAlpha(O2ContextFillColor(self), alpha);
|
|
O2ContextSetFillColorWithColor(self, color);
|
|
O2ColorRelease(color);
|
|
}
|
|
|
|
- (void) setGrayFillColor: (O2Float) gray {
|
|
O2Float alpha = O2ColorGetAlpha(O2ContextFillColor(self));
|
|
O2ContextSetGrayFillColor(self, gray, alpha);
|
|
}
|
|
|
|
- (void) setFillColorRed: (O2Float) r green: (O2Float) g blue: (O2Float) b {
|
|
O2Float alpha = O2ColorGetAlpha(O2ContextFillColor(self));
|
|
O2ContextSetRGBFillColor(self, r, g, b, alpha);
|
|
}
|
|
|
|
- (void) setFillColorC: (O2Float) c
|
|
m: (O2Float) m
|
|
y: (O2Float) y
|
|
k: (O2Float) k
|
|
{
|
|
O2Float alpha = O2ColorGetAlpha(O2ContextFillColor(self));
|
|
O2ContextSetCMYKFillColor(self, c, m, y, k, alpha);
|
|
}
|
|
|
|
- (void) setAlpha: (O2Float) alpha {
|
|
O2GStateSetAlpha(O2ContextCurrentGState(self), alpha);
|
|
if ([self supportsGlobalAlpha] == NO) {
|
|
[self setStrokeAlpha: alpha];
|
|
[self setFillAlpha: alpha];
|
|
}
|
|
}
|
|
|
|
- (BOOL) supportsGlobalAlpha {
|
|
return NO;
|
|
}
|
|
|
|
- (BOOL) isBitmapContext {
|
|
return YES;
|
|
}
|
|
|
|
- (void) drawPath: (O2PathDrawingMode) pathMode {
|
|
O2InvalidAbstractInvocation();
|
|
// reset path in subclass
|
|
}
|
|
|
|
- (void) replacePathWithStrokedPath {
|
|
O2UnimplementedFunction();
|
|
}
|
|
|
|
- (void) drawShading: (O2Shading *) shading {
|
|
O2InvalidAbstractInvocation();
|
|
}
|
|
|
|
- (void) drawImage: (O2Image *) image inRect: (O2Rect) rect {
|
|
O2InvalidAbstractInvocation();
|
|
}
|
|
|
|
- (void) drawLayer: (O2LayerRef) layer inRect: (O2Rect) rect {
|
|
O2InvalidAbstractInvocation();
|
|
}
|
|
|
|
- (void) flush {
|
|
// do nothing
|
|
}
|
|
|
|
- (void) synchronize {
|
|
// do nothing
|
|
}
|
|
|
|
- (BOOL) resizeWithNewSize: (O2Size) size {
|
|
return NO;
|
|
}
|
|
|
|
- (void) beginPage: (const O2Rect *) mediaBox {
|
|
// do nothing
|
|
}
|
|
|
|
- (void) endPage {
|
|
// do nothing
|
|
}
|
|
|
|
- (void) close {
|
|
// do nothing
|
|
}
|
|
|
|
- (O2Size) size {
|
|
return O2SizeMake(0, 0);
|
|
}
|
|
|
|
- (O2ContextRef) createCompatibleContextWithSize: (O2Size) size
|
|
unused: (NSDictionary *) unused
|
|
{
|
|
return [[[self class] alloc] initWithSize: size context: self];
|
|
}
|
|
|
|
- (BOOL) getImageableRect: (O2Rect *) rect {
|
|
return NO;
|
|
}
|
|
|
|
// temporary
|
|
|
|
- (void) setAntialiasingQuality: (int) value {
|
|
[O2ContextCurrentGState(self) setAntialiasingQuality: value];
|
|
}
|
|
|
|
- (void) copyBitsInRect: (O2Rect) rect
|
|
toPoint: (O2Point) point
|
|
gState: (int) gState
|
|
{
|
|
O2InvalidAbstractInvocation();
|
|
}
|
|
|
|
- (NSData *) captureBitmapInRect: (NSRect) rect {
|
|
O2InvalidAbstractInvocation();
|
|
return nil;
|
|
}
|
|
|
|
/*
|
|
Notes: OSX generates a clip mask at fill time using the current aliasing
|
|
setting. Once the fill is complete the clip mask persists with the next
|
|
clip/fill. This means you can turn off AA, create a clip path, fill, turn on
|
|
AA, create another clip path, fill, and edges from the first path will be
|
|
aliased, and ones from the second will not. PDF does not dictate aliasing
|
|
behavior, so while this is not really expected behavior, it is not a bug.
|
|
|
|
*/
|
|
|
|
- (void) clipToState: (O2ClipState *) clipState {
|
|
O2InvalidAbstractInvocation();
|
|
}
|
|
|
|
O2ContextRef O2ContextRetain(O2ContextRef self) {
|
|
return (self != NULL) ? (O2ContextRef) CFRetain(self) : NULL;
|
|
}
|
|
|
|
void O2ContextRelease(O2ContextRef self) {
|
|
if (self != NULL)
|
|
CFRelease(self);
|
|
}
|
|
|
|
// context state
|
|
void O2ContextSetAllowsAntialiasing(O2ContextRef self, BOOL yesOrNo) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
self->_allowsAntialiasing = yesOrNo;
|
|
}
|
|
|
|
// layers
|
|
void O2ContextBeginTransparencyLayer(O2ContextRef self, NSDictionary *unused) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[self beginTransparencyLayerWithInfo: unused];
|
|
}
|
|
|
|
void O2ContextEndTransparencyLayer(O2ContextRef self) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[self endTransparencyLayer];
|
|
}
|
|
|
|
// path
|
|
BOOL O2ContextIsPathEmpty(O2ContextRef self) {
|
|
if (self == nil)
|
|
return YES;
|
|
|
|
return (self->_path == nil) ? YES : O2PathIsEmpty(self->_path);
|
|
}
|
|
|
|
O2Point O2ContextGetPathCurrentPoint(O2ContextRef self) {
|
|
if (self == nil)
|
|
return O2PointZero;
|
|
|
|
return (self->_path == nil) ? O2PointZero
|
|
: O2PathGetCurrentPoint(self->_path);
|
|
}
|
|
|
|
O2Rect O2ContextGetPathBoundingBox(O2ContextRef self) {
|
|
if (self == nil)
|
|
return O2RectZero;
|
|
|
|
return (self->_path == nil) ? O2RectZero
|
|
: O2PathGetBoundingBox(self->_path);
|
|
}
|
|
|
|
BOOL O2ContextPathContainsPoint(O2ContextRef self, O2Point point,
|
|
O2PathDrawingMode pathMode)
|
|
{
|
|
if (self == nil)
|
|
return NO;
|
|
|
|
O2AffineTransform ctm = O2ContextCurrentGState(self)->_deviceSpaceTransform;
|
|
|
|
// FIX evenOdd
|
|
return O2PathContainsPoint(self->_path, &ctm, point, NO);
|
|
}
|
|
|
|
void O2ContextBeginPath(O2ContextRef self) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2PathReset(self->_path);
|
|
}
|
|
|
|
void O2ContextClosePath(O2ContextRef self) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2PathCloseSubpath(self->_path);
|
|
}
|
|
|
|
/* Path building is affected by the CTM, we transform them here into base
|
|
coordinates (first quadrant, no transformation)
|
|
|
|
A backend can then convert them to where it needs them, base, current, or
|
|
device space.
|
|
*/
|
|
|
|
void O2ContextMoveToPoint(O2ContextRef self, O2Float x, O2Float y) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform ctm =
|
|
O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
|
|
O2PathMoveToPoint(self->_path, &ctm, x, y);
|
|
}
|
|
|
|
void O2ContextAddLineToPoint(O2ContextRef self, O2Float x, O2Float y) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform ctm =
|
|
O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
|
|
O2PathAddLineToPoint(self->_path, &ctm, x, y);
|
|
}
|
|
|
|
void O2ContextAddCurveToPoint(O2ContextRef self, O2Float cx1, O2Float cy1,
|
|
O2Float cx2, O2Float cy2, O2Float x, O2Float y)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform ctm =
|
|
O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
|
|
O2PathAddCurveToPoint(self->_path, &ctm, cx1, cy1, cx2, cy2, x, y);
|
|
}
|
|
|
|
void O2ContextAddQuadCurveToPoint(O2ContextRef self, O2Float cx1, O2Float cy1,
|
|
O2Float x, O2Float y)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform ctm =
|
|
O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
|
|
O2PathAddQuadCurveToPoint(self->_path, &ctm, cx1, cy1, x, y);
|
|
}
|
|
|
|
void O2ContextAddLines(O2ContextRef self, const O2Point *points,
|
|
NSUInteger count)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform ctm =
|
|
O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
|
|
O2PathAddLines(self->_path, &ctm, points, count);
|
|
}
|
|
|
|
void O2ContextAddRect(O2ContextRef self, O2Rect rect) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform ctm =
|
|
O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
|
|
O2PathAddRect(self->_path, &ctm, rect);
|
|
}
|
|
|
|
void O2ContextAddRects(O2ContextRef self, const O2Rect *rects, NSUInteger count)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform ctm =
|
|
O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
|
|
O2PathAddRects(self->_path, &ctm, rects, count);
|
|
}
|
|
|
|
void O2ContextAddArc(O2ContextRef self, O2Float x, O2Float y, O2Float radius,
|
|
O2Float startRadian, O2Float endRadian, BOOL clockwise)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform ctm =
|
|
O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
|
|
O2PathAddArc(self->_path, &ctm, x, y, radius, startRadian, endRadian,
|
|
clockwise);
|
|
}
|
|
|
|
void O2ContextAddArcToPoint(O2ContextRef self, O2Float x1, O2Float y1,
|
|
O2Float x2, O2Float y2, O2Float radius)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform ctm =
|
|
O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
|
|
O2PathAddArcToPoint(self->_path, &ctm, x1, y1, x2, y2, radius);
|
|
}
|
|
|
|
void O2ContextAddEllipseInRect(O2ContextRef self, O2Rect rect) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform ctm =
|
|
O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
|
|
O2PathAddEllipseInRect(self->_path, &ctm, rect);
|
|
}
|
|
|
|
void O2ContextAddPath(O2ContextRef self, O2PathRef path) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform ctm =
|
|
O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
|
|
O2PathAddPath(self->_path, &ctm, path);
|
|
}
|
|
|
|
void O2ContextReplacePathWithStrokedPath(O2ContextRef self) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[self replacePathWithStrokedPath];
|
|
}
|
|
|
|
O2Path *O2ContextCopyPath(O2ContextRef self) {
|
|
if (self == nil)
|
|
return nil;
|
|
|
|
return [self->_path copy];
|
|
}
|
|
|
|
// gstate
|
|
|
|
void O2ContextSaveGState(O2ContextRef self) {
|
|
if (self == nil) {
|
|
return;
|
|
}
|
|
|
|
O2GState *current = O2ContextCurrentGState(self), *next;
|
|
|
|
next = O2GStateCopyWithZone(current, NULL);
|
|
[self->_stateStack addObject: next];
|
|
self->_currentState = next;
|
|
[next release];
|
|
}
|
|
|
|
void O2ContextRestoreGState(O2ContextRef self) {
|
|
if (self == nil) {
|
|
return;
|
|
}
|
|
|
|
[self->_stateStack removeLastObject];
|
|
self->_currentState = [self->_stateStack lastObject];
|
|
|
|
O2GState *gState = O2ContextCurrentGState(self);
|
|
|
|
// FIXME, this could be conditional by comparing to previous font
|
|
gState->_fontIsDirty = YES;
|
|
gState->_fillColorIsDirty = YES;
|
|
|
|
[self clipToState: O2GStateClipState(gState)];
|
|
}
|
|
|
|
O2AffineTransform O2ContextGetUserSpaceToDeviceSpaceTransform(O2ContextRef self)
|
|
{
|
|
if (self == nil)
|
|
return O2AffineTransformIdentity;
|
|
|
|
return O2ContextCurrentGState(self)->_deviceSpaceTransform;
|
|
}
|
|
|
|
O2AffineTransform O2ContextGetCTM(O2ContextRef self) {
|
|
if (self == nil)
|
|
return O2AffineTransformIdentity;
|
|
|
|
return O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
}
|
|
|
|
O2Rect O2ContextGetClipBoundingBox(O2ContextRef self) {
|
|
if (self == nil)
|
|
return O2RectZero;
|
|
|
|
return [O2ContextCurrentGState(self) clipBoundingBox];
|
|
}
|
|
|
|
O2AffineTransform O2ContextGetTextMatrix(O2ContextRef self) {
|
|
if (self == nil)
|
|
return O2AffineTransformIdentity;
|
|
|
|
return self->_textMatrix;
|
|
}
|
|
|
|
O2InterpolationQuality O2ContextGetInterpolationQuality(O2ContextRef self) {
|
|
if (self == nil)
|
|
return 0;
|
|
|
|
return [O2ContextCurrentGState(self) interpolationQuality];
|
|
}
|
|
|
|
O2Point O2ContextGetTextPosition(O2ContextRef self) {
|
|
if (self == nil)
|
|
return O2PointZero;
|
|
|
|
O2Point result = {self->_textMatrix.tx, self->_textMatrix.ty};
|
|
return result;
|
|
}
|
|
|
|
O2Point O2ContextConvertPointToDeviceSpace(O2ContextRef self, O2Point point) {
|
|
if (self == nil)
|
|
return O2PointZero;
|
|
|
|
return [O2ContextCurrentGState(self) convertPointToDeviceSpace: point];
|
|
}
|
|
|
|
O2Point O2ContextConvertPointToUserSpace(O2ContextRef self, O2Point point) {
|
|
if (self == nil)
|
|
return O2PointZero;
|
|
|
|
return [O2ContextCurrentGState(self) convertPointToUserSpace: point];
|
|
}
|
|
|
|
O2Size O2ContextConvertSizeToDeviceSpace(O2ContextRef self, O2Size size) {
|
|
if (self == nil)
|
|
return O2SizeZero;
|
|
|
|
return [O2ContextCurrentGState(self) convertSizeToDeviceSpace: size];
|
|
}
|
|
|
|
O2Size O2ContextConvertSizeToUserSpace(O2ContextRef self, O2Size size) {
|
|
if (self == nil)
|
|
return O2SizeZero;
|
|
|
|
return [O2ContextCurrentGState(self) convertSizeToUserSpace: size];
|
|
}
|
|
|
|
O2Rect O2ContextConvertRectToDeviceSpace(O2ContextRef self, O2Rect rect) {
|
|
if (self == nil)
|
|
return O2RectZero;
|
|
|
|
return [O2ContextCurrentGState(self) convertRectToDeviceSpace: rect];
|
|
}
|
|
|
|
O2Rect O2ContextConvertRectToUserSpace(O2ContextRef self, O2Rect rect) {
|
|
if (self == nil)
|
|
return O2RectZero;
|
|
|
|
return [O2ContextCurrentGState(self) convertRectToUserSpace: rect];
|
|
}
|
|
|
|
void O2ContextConcatCTM(O2ContextRef self, O2AffineTransform matrix) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GStateConcatCTM(O2ContextCurrentGState(self), matrix);
|
|
}
|
|
|
|
void O2ContextTranslateCTM(O2ContextRef self, O2Float translatex,
|
|
O2Float translatey)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ContextConcatCTM(
|
|
self, O2AffineTransformMakeTranslation(translatex, translatey));
|
|
}
|
|
|
|
void O2ContextScaleCTM(O2ContextRef self, O2Float scalex, O2Float scaley) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ContextConcatCTM(self, O2AffineTransformMakeScale(scalex, scaley));
|
|
}
|
|
|
|
void O2ContextRotateCTM(O2ContextRef self, O2Float radians) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ContextConcatCTM(self, O2AffineTransformMakeRotation(radians));
|
|
}
|
|
|
|
void O2ContextClip(O2ContextRef self) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
if (O2PathIsEmpty(self->_path))
|
|
return;
|
|
|
|
O2GState *gState = O2ContextCurrentGState(self);
|
|
|
|
O2PathApplyTransform(self->_path,
|
|
O2AffineTransformInvert(gState->_userSpaceTransform));
|
|
O2PathApplyTransform(self->_path, gState->_deviceSpaceTransform);
|
|
|
|
O2GStateAddClipToPath(gState, self->_path);
|
|
|
|
O2PathReset(self->_path);
|
|
|
|
[self clipToState: O2GStateClipState(gState)];
|
|
}
|
|
|
|
void O2ContextEOClip(O2ContextRef self) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
if (O2PathIsEmpty(self->_path))
|
|
return;
|
|
|
|
O2GState *gState = O2ContextCurrentGState(self);
|
|
|
|
O2PathApplyTransform(self->_path,
|
|
O2AffineTransformInvert(gState->_userSpaceTransform));
|
|
O2PathApplyTransform(self->_path, gState->_deviceSpaceTransform);
|
|
|
|
O2GStateAddEvenOddClipToPath(gState, self->_path);
|
|
|
|
O2PathReset(self->_path);
|
|
|
|
[self clipToState: O2GStateClipState(gState)];
|
|
}
|
|
|
|
void O2ContextClipToMask(O2ContextRef self, O2Rect rect, O2ImageRef image) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GState *gState = O2ContextCurrentGState(self);
|
|
|
|
O2GStateAddClipToMask(gState, image, rect);
|
|
|
|
[self clipToState: O2GStateClipState(gState)];
|
|
}
|
|
|
|
void O2ContextClipToRect(O2ContextRef self, O2Rect rect) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform ctm =
|
|
O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
|
|
O2PathReset(self->_path);
|
|
O2PathAddRect(self->_path, &ctm, rect);
|
|
O2ContextClip(self);
|
|
}
|
|
|
|
void O2ContextClipToRects(O2ContextRef self, const O2Rect *rects,
|
|
NSUInteger count)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform ctm =
|
|
O2GStateUserSpaceTransform(O2ContextCurrentGState(self));
|
|
|
|
O2PathReset(self->_path);
|
|
O2PathAddRects(self->_path, &ctm, rects, count);
|
|
O2ContextClip(self);
|
|
}
|
|
|
|
void O2ContextSetStrokeColorSpace(O2ContextRef self, O2ColorSpaceRef colorSpace)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
int i, length = O2ColorSpaceGetNumberOfComponents(colorSpace);
|
|
O2Float components[length + 1];
|
|
|
|
for (i = 0; i < length; i++)
|
|
components[i] = 0;
|
|
components[i] = 1;
|
|
|
|
O2ColorRef color = O2ColorCreate(colorSpace, components);
|
|
|
|
O2ContextSetStrokeColorWithColor(self, color);
|
|
|
|
O2ColorRelease(color);
|
|
}
|
|
|
|
void O2ContextSetFillColorSpace(O2ContextRef self, O2ColorSpaceRef colorSpace) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
int i, length = O2ColorSpaceGetNumberOfComponents(colorSpace);
|
|
O2Float components[length + 1];
|
|
|
|
for (i = 0; i < length; i++)
|
|
components[i] = 0;
|
|
components[i] = 1;
|
|
|
|
O2ColorRef color = O2ColorCreate(colorSpace, components);
|
|
|
|
O2ContextSetFillColorWithColor(self, color);
|
|
|
|
O2ColorRelease(color);
|
|
}
|
|
|
|
void O2ContextSetStrokeColor(O2ContextRef self, const O2Float *components) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ColorSpaceRef colorSpace =
|
|
O2ColorGetColorSpace(O2ContextStrokeColor(self));
|
|
O2ColorRef color = O2ColorCreate(colorSpace, components);
|
|
|
|
O2ContextSetStrokeColorWithColor(self, color);
|
|
|
|
O2ColorRelease(color);
|
|
}
|
|
|
|
void O2ContextSetStrokeColorWithColor(O2ContextRef self, O2ColorRef color) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GStateSetStrokeColor(O2ContextCurrentGState(self), color);
|
|
}
|
|
|
|
void O2ContextSetGrayStrokeColor(O2ContextRef self, O2Float gray, O2Float alpha)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ColorSpaceRef colorSpace = O2ColorSpaceCreateDeviceGray();
|
|
O2Float components[2] = {gray, alpha};
|
|
O2ColorRef color = O2ColorCreate(colorSpace, components);
|
|
|
|
O2ContextSetStrokeColorWithColor(self, color);
|
|
|
|
O2ColorRelease(color);
|
|
O2ColorSpaceRelease(colorSpace);
|
|
}
|
|
|
|
void O2ContextSetRGBStrokeColor(O2ContextRef self, O2Float r, O2Float g,
|
|
O2Float b, O2Float alpha)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ColorSpaceRef colorSpace = O2ColorSpaceCreateDeviceRGB();
|
|
O2Float components[4] = {r, g, b, alpha};
|
|
O2ColorRef color = O2ColorCreate(colorSpace, components);
|
|
|
|
O2ContextSetStrokeColorWithColor(self, color);
|
|
|
|
O2ColorRelease(color);
|
|
O2ColorSpaceRelease(colorSpace);
|
|
}
|
|
|
|
void O2ContextSetCMYKStrokeColor(O2ContextRef self, O2Float c, O2Float m,
|
|
O2Float y, O2Float k, O2Float alpha)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ColorSpaceRef colorSpace = O2ColorSpaceCreateDeviceCMYK();
|
|
O2Float components[5] = {c, m, y, k, alpha};
|
|
O2ColorRef color = O2ColorCreate(colorSpace, components);
|
|
|
|
O2ContextSetStrokeColorWithColor(self, color);
|
|
|
|
O2ColorRelease(color);
|
|
O2ColorSpaceRelease(colorSpace);
|
|
}
|
|
|
|
void O2ContextSetFillColor(O2ContextRef self, const O2Float *components) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ColorSpaceRef colorSpace = O2ColorGetColorSpace(O2ContextFillColor(self));
|
|
O2ColorRef color = O2ColorCreate(colorSpace, components);
|
|
|
|
O2ContextSetFillColorWithColor(self, color);
|
|
|
|
O2ColorRelease(color);
|
|
}
|
|
|
|
void O2ContextSetFillColorWithColor(O2ContextRef self, O2ColorRef color) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GStateSetFillColor(O2ContextCurrentGState(self), color);
|
|
}
|
|
|
|
void O2ContextSetGrayFillColor(O2ContextRef self, O2Float gray, O2Float alpha) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ColorSpaceRef colorSpace = O2ColorSpaceCreateDeviceGray();
|
|
O2Float components[2] = {gray, alpha};
|
|
O2ColorRef color = O2ColorCreate(colorSpace, components);
|
|
|
|
O2ContextSetFillColorWithColor(self, color);
|
|
|
|
O2ColorRelease(color);
|
|
O2ColorSpaceRelease(colorSpace);
|
|
}
|
|
|
|
void O2ContextSetRGBFillColor(O2ContextRef self, O2Float r, O2Float g,
|
|
O2Float b, O2Float alpha)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ColorSpaceRef colorSpace = O2ColorSpaceCreateDeviceRGB();
|
|
O2Float components[4] = {r, g, b, alpha};
|
|
O2ColorRef color = O2ColorCreate(colorSpace, components);
|
|
|
|
O2ContextSetFillColorWithColor(self, color);
|
|
|
|
O2ColorRelease(color);
|
|
O2ColorSpaceRelease(colorSpace);
|
|
}
|
|
|
|
void O2ContextSetCMYKFillColor(O2ContextRef self, O2Float c, O2Float m,
|
|
O2Float y, O2Float k, O2Float alpha)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ColorSpaceRef colorSpace = O2ColorSpaceCreateDeviceCMYK();
|
|
O2Float components[5] = {c, m, y, k, alpha};
|
|
O2ColorRef color = O2ColorCreate(colorSpace, components);
|
|
|
|
O2ContextSetFillColorWithColor(self, color);
|
|
|
|
O2ColorRelease(color);
|
|
O2ColorSpaceRelease(colorSpace);
|
|
}
|
|
|
|
void O2ContextSetAlpha(O2ContextRef self, O2Float alpha) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[self setAlpha: alpha];
|
|
}
|
|
|
|
void O2ContextSetPatternPhase(O2ContextRef self, O2Size phase) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GStateSetPatternPhase(O2ContextCurrentGState(self), phase);
|
|
}
|
|
|
|
void O2ContextSetStrokePattern(O2ContextRef self, O2PatternRef pattern,
|
|
const O2Float *components)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
[O2ContextCurrentGState(self) setStrokePattern: pattern
|
|
components: components];
|
|
}
|
|
|
|
void O2ContextSetFillPattern(O2ContextRef self, O2PatternRef pattern,
|
|
const O2Float *components)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
[O2ContextCurrentGState(self) setFillPattern: pattern
|
|
components: components];
|
|
}
|
|
|
|
void O2ContextSetTextMatrix(O2ContextRef self, O2AffineTransform matrix) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
self->_textMatrix = matrix;
|
|
O2ContextCurrentGState(self)->_fontIsDirty = YES;
|
|
}
|
|
|
|
void O2ContextSetTextPosition(O2ContextRef self, O2Float x, O2Float y) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
self->_textMatrix.tx = x;
|
|
self->_textMatrix.ty = y;
|
|
}
|
|
|
|
void O2ContextSetCharacterSpacing(O2ContextRef self, O2Float spacing) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GStateSetCharacterSpacing(O2ContextCurrentGState(self), spacing);
|
|
}
|
|
|
|
void O2ContextSetTextDrawingMode(O2ContextRef self, O2TextDrawingMode textMode)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
[O2ContextCurrentGState(self) setTextDrawingMode: textMode];
|
|
}
|
|
|
|
void O2ContextSetFont(O2ContextRef self, O2FontRef font) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GStateSetFont(O2ContextCurrentGState(self), font);
|
|
}
|
|
|
|
void O2ContextSetFontSize(O2ContextRef self, O2Float size) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GStateSetFontSize(O2ContextCurrentGState(self), size);
|
|
}
|
|
|
|
void O2ContextSelectFont(O2ContextRef self, const char *name, O2Float size,
|
|
O2TextEncoding encoding)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
[O2ContextCurrentGState(self) selectFontWithName: name
|
|
size: size
|
|
encoding: encoding];
|
|
}
|
|
|
|
void O2ContextSetShouldSmoothFonts(O2ContextRef self, BOOL yesOrNo) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[O2ContextCurrentGState(self) setShouldSmoothFonts: yesOrNo];
|
|
}
|
|
|
|
void O2ContextSetLineWidth(O2ContextRef self, O2Float width) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GStateSetLineWidth(O2ContextCurrentGState(self), width);
|
|
}
|
|
|
|
void O2ContextSetLineCap(O2ContextRef self, O2LineCap lineCap) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GStateSetLineCap(O2ContextCurrentGState(self), lineCap);
|
|
}
|
|
|
|
void O2ContextSetLineJoin(O2ContextRef self, O2LineJoin lineJoin) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GStateSetLineJoin(O2ContextCurrentGState(self), lineJoin);
|
|
}
|
|
|
|
void O2ContextSetMiterLimit(O2ContextRef self, O2Float miterLimit) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GStateSetMiterLimit(O2ContextCurrentGState(self), miterLimit);
|
|
}
|
|
|
|
void O2ContextSetLineDash(O2ContextRef self, O2Float phase,
|
|
const O2Float *lengths, NSUInteger count)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GStateSetLineDash(O2ContextCurrentGState(self), phase, lengths, count);
|
|
}
|
|
|
|
void O2ContextSetRenderingIntent(O2ContextRef self,
|
|
O2ColorRenderingIntent renderingIntent)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
[O2ContextCurrentGState(self) setRenderingIntent: renderingIntent];
|
|
}
|
|
|
|
void O2ContextSetBlendMode(O2ContextRef self, O2BlendMode blendMode) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GStateSetBlendMode(O2ContextCurrentGState(self), blendMode);
|
|
}
|
|
|
|
void O2ContextSetFlatness(O2ContextRef self, O2Float flatness) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[O2ContextCurrentGState(self) setFlatness: flatness];
|
|
}
|
|
|
|
void O2ContextSetInterpolationQuality(O2ContextRef self,
|
|
O2InterpolationQuality quality)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
[O2ContextCurrentGState(self) setInterpolationQuality: quality];
|
|
}
|
|
|
|
void O2ContextSetShadowWithColor(O2ContextRef self, O2Size offset, O2Float blur,
|
|
O2ColorRef color)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
[O2ContextCurrentGState(self) setShadowOffset: offset
|
|
blur: blur
|
|
color: color];
|
|
}
|
|
|
|
void O2ContextSetShadow(O2ContextRef self, O2Size offset, O2Float blur) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[O2ContextCurrentGState(self) setShadowOffset: offset blur: blur];
|
|
}
|
|
|
|
void O2ContextSetShouldAntialias(O2ContextRef self, BOOL yesOrNo) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[O2ContextCurrentGState(self) setShouldAntialias: yesOrNo];
|
|
}
|
|
|
|
// drawing
|
|
void O2ContextStrokeLineSegments(O2ContextRef self, const O2Point *points,
|
|
NSUInteger count)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
int i;
|
|
|
|
O2ContextBeginPath(self);
|
|
for (i = 0; i < count; i += 2) {
|
|
O2ContextMoveToPoint(self, points[i].x, points[i].y);
|
|
O2ContextAddLineToPoint(self, points[i + 1].x, points[i + 1].y);
|
|
}
|
|
O2ContextStrokePath(self);
|
|
}
|
|
|
|
void O2ContextStrokeRect(O2ContextRef self, O2Rect rect) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ContextBeginPath(self);
|
|
O2ContextAddRect(self, rect);
|
|
O2ContextStrokePath(self);
|
|
}
|
|
|
|
void O2ContextStrokeRectWithWidth(O2ContextRef self, O2Rect rect, O2Float width)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ContextSaveGState(self);
|
|
O2ContextSetLineWidth(self, width);
|
|
O2ContextBeginPath(self);
|
|
O2ContextAddRect(self, rect);
|
|
O2ContextStrokePath(self);
|
|
O2ContextRestoreGState(self);
|
|
}
|
|
|
|
void O2ContextStrokeEllipseInRect(O2ContextRef self, O2Rect rect) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ContextBeginPath(self);
|
|
O2ContextAddEllipseInRect(self, rect);
|
|
O2ContextStrokePath(self);
|
|
}
|
|
|
|
void O2ContextFillRect(O2ContextRef self, O2Rect rect) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ContextFillRects(self, &rect, 1);
|
|
}
|
|
|
|
void O2ContextFillRects(O2ContextRef self, const O2Rect *rects,
|
|
NSUInteger count)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ContextBeginPath(self);
|
|
O2ContextAddRects(self, rects, count);
|
|
O2ContextFillPath(self);
|
|
}
|
|
|
|
void O2ContextFillEllipseInRect(O2ContextRef self, O2Rect rect) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ContextBeginPath(self);
|
|
O2ContextAddEllipseInRect(self, rect);
|
|
O2ContextFillPath(self);
|
|
}
|
|
|
|
void O2ContextDrawPath(O2ContextRef self, O2PathDrawingMode pathMode) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[self drawPath: pathMode];
|
|
}
|
|
|
|
void O2ContextStrokePath(O2ContextRef self) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ContextDrawPath(self, kO2PathStroke);
|
|
}
|
|
|
|
void O2ContextFillPath(O2ContextRef self) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ContextDrawPath(self, kO2PathFill);
|
|
}
|
|
|
|
void O2ContextEOFillPath(O2ContextRef self) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ContextDrawPath(self, kO2PathEOFill);
|
|
}
|
|
|
|
void O2ContextClearRect(O2ContextRef self, O2Rect rect) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
// doc.s are not clear. tests say O2ContextClearRect resets the path and
|
|
// does not affect gstate color
|
|
O2ContextSaveGState(self);
|
|
O2ContextSetBlendMode(self,
|
|
kO2BlendModeCopy); // does it set the blend mode?
|
|
O2ContextSetGrayFillColor(self, 0, 0);
|
|
O2ContextFillRect(self, rect);
|
|
O2ContextRestoreGState(self);
|
|
}
|
|
|
|
void O2ContextShowGlyphs(O2ContextRef self, const O2Glyph *glyphs,
|
|
NSUInteger count)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
self->_showGlyphsFunction(self, NULL, glyphs, NULL, count);
|
|
}
|
|
|
|
void O2ContextShowGlyphsAtPoint(O2ContextRef self, O2Float x, O2Float y,
|
|
const O2Glyph *glyphs, NSUInteger count)
|
|
{
|
|
O2ContextSetTextPosition(self, x, y);
|
|
O2ContextShowGlyphs(self, glyphs, count);
|
|
}
|
|
|
|
- (void) showGlyphs: (const O2Glyph *) glyphs
|
|
advances: (const O2Size *) advances
|
|
count: (NSUInteger) count
|
|
{
|
|
#if 1
|
|
O2InvalidAbstractInvocation();
|
|
#else
|
|
O2AffineTransform textMatrix = O2ContextGetTextMatrix(self);
|
|
O2Float x = textMatrix.tx;
|
|
O2Float y = textMatrix.ty;
|
|
int i;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
[self showGlyphs: glyphs + i count: 1];
|
|
|
|
O2Size advance = O2SizeApplyAffineTransform(advances[i], textMatrix);
|
|
|
|
x += advance.width;
|
|
y += advance.height;
|
|
O2ContextSetTextPosition(self, x, y);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void O2ContextShowGlyphsWithAdvances(O2ContextRef self, const O2Glyph *glyphs,
|
|
const O2Size *advances, NSUInteger count)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
self->_showGlyphsFunction(self, NULL, glyphs, advances, count);
|
|
}
|
|
|
|
void O2ContextDefaultShowText(O2ContextRef self, const char *text,
|
|
NSUInteger length)
|
|
{
|
|
O2GState *gState = O2ContextCurrentGState(self);
|
|
O2Encoding *encoding = O2GStateEncoding(gState);
|
|
O2PDFCharWidths *widths = O2GStateCharWidths(gState);
|
|
O2Glyph glyphs[length];
|
|
|
|
O2EncodingGetGlyphsForBytes(encoding, glyphs, (const uint8_t *) text,
|
|
length);
|
|
if (widths == nil && gState->_characterSpacing == 0)
|
|
self->_showGlyphsFunction(self, NULL, glyphs, NULL, length);
|
|
else {
|
|
O2Size advances[length];
|
|
int i;
|
|
|
|
if (widths != nil)
|
|
O2PDFCharWidthsGetAdvances(widths, advances, (const uint8_t *) text,
|
|
length);
|
|
else
|
|
O2ContextGetDefaultAdvances(self, glyphs, advances, length);
|
|
|
|
for (i = 0; i < length; i++) {
|
|
advances[i].width += gState->_characterSpacing;
|
|
}
|
|
|
|
self->_showGlyphsFunction(self, NULL, glyphs, advances, length);
|
|
}
|
|
}
|
|
|
|
void O2ContextShowText(O2ContextRef self, const char *text, NSUInteger length) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
self->_showTextFunction(self, text, length);
|
|
}
|
|
|
|
void O2ContextShowTextAtPoint(O2ContextRef self, O2Float x, O2Float y,
|
|
const char *text, NSUInteger count)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2ContextSetTextPosition(self, x, y);
|
|
O2ContextShowText(self, text, count);
|
|
}
|
|
|
|
void O2ContextDrawShading(O2ContextRef self, O2ShadingRef shading) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[self drawShading: shading];
|
|
}
|
|
|
|
void O2ContextDrawImage(O2ContextRef self, O2Rect rect, O2ImageRef image) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[self drawImage: image inRect: rect];
|
|
}
|
|
|
|
void O2ContextDrawLayerAtPoint(O2ContextRef self, O2Point point,
|
|
O2LayerRef layer)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2Size size = O2LayerGetSize(layer);
|
|
O2Rect rect = {point, size};
|
|
|
|
O2ContextDrawLayerInRect(self, rect, layer);
|
|
}
|
|
|
|
void O2ContextDrawLayerInRect(O2ContextRef self, O2Rect rect, O2LayerRef layer)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
[self drawLayer: layer inRect: rect];
|
|
}
|
|
|
|
void O2ContextDrawPDFPage(O2ContextRef self, O2PDFPageRef page) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
// Per doc.s, these are initialized at the beginning of each page only
|
|
|
|
O2ContextSetCharacterSpacing(self, 0);
|
|
O2ContextSetWordSpacing(self, 0);
|
|
O2ContextSetTextHorizontalScaling(self, 100);
|
|
O2ContextSetTextLeading(self, 0);
|
|
O2ContextSetTextDrawingMode(self, 0);
|
|
O2ContextSetTextRise(self, 0);
|
|
|
|
[page drawInContext: self];
|
|
|
|
O2ContextSetTextLineMatrix(self, O2AffineTransformIdentity);
|
|
O2ContextSetTextMatrix(self, O2AffineTransformIdentity);
|
|
}
|
|
|
|
void O2ContextFlush(O2ContextRef self) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[self flush];
|
|
}
|
|
|
|
void O2ContextSynchronize(O2ContextRef self) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[self synchronize];
|
|
}
|
|
|
|
// pagination
|
|
|
|
void O2ContextBeginPage(O2ContextRef self, const O2Rect *mediaBox) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[self beginPage: mediaBox];
|
|
}
|
|
|
|
void O2ContextEndPage(O2ContextRef self) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
[self endPage];
|
|
}
|
|
|
|
// **PRIVATE** These are private in Apple's implementation as well as ours.
|
|
|
|
void O2ContextSetTextLineMatrix(O2ContextRef self, O2AffineTransform matrix) {
|
|
self->_textLineMatrix = matrix;
|
|
}
|
|
|
|
O2AffineTransform O2ContextGetTextLineMatrix(O2ContextRef self) {
|
|
return self->_textLineMatrix;
|
|
}
|
|
|
|
O2Float O2ContextGetTextLeading(O2ContextRef self) {
|
|
return O2GStateTextLeading(O2ContextCurrentGState(self));
|
|
}
|
|
|
|
void O2ContextSetTextLeading(O2ContextRef self, O2Float value) {
|
|
O2GStateSetTextLeading(O2ContextCurrentGState(self), value);
|
|
}
|
|
|
|
void O2ContextSetWordSpacing(O2ContextRef self, O2Float value) {
|
|
O2GStateSetWordSpacing(O2ContextCurrentGState(self), value);
|
|
}
|
|
|
|
void O2ContextSetTextRise(O2ContextRef self, O2Float value) {
|
|
O2GStateSetTextRise(O2ContextCurrentGState(self), value);
|
|
}
|
|
|
|
void O2ContextSetTextHorizontalScaling(O2ContextRef self, O2Float value) {
|
|
O2GStateSetTextHorizontalScaling(O2ContextCurrentGState(self), value);
|
|
}
|
|
|
|
void O2ContextSetEncoding(O2ContextRef self, O2Encoding *value) {
|
|
O2GStateSetFontEncoding(O2ContextCurrentGState(self), value);
|
|
}
|
|
|
|
void O2ContextSetPDFCharWidths(O2ContextRef self, O2PDFCharWidths *value) {
|
|
[O2ContextCurrentGState(self) setPDFCharWidths: value];
|
|
}
|
|
|
|
void O2ContextSetCTM(O2ContextRef self, O2AffineTransform matrix) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2AffineTransform deviceTransform = self->_userToDeviceTransform;
|
|
|
|
deviceTransform = O2AffineTransformConcat(matrix, deviceTransform);
|
|
|
|
O2GStateSetDeviceSpaceCTM(O2ContextCurrentGState(self), deviceTransform);
|
|
|
|
O2GStateSetUserSpaceCTM(O2ContextCurrentGState(self), matrix);
|
|
}
|
|
|
|
void O2ContextResetClip(O2ContextRef self) {
|
|
if (self == nil)
|
|
return;
|
|
|
|
O2GState *gState = O2ContextCurrentGState(self);
|
|
|
|
O2GStateResetClip(gState);
|
|
|
|
[self clipToState: O2GStateClipState(gState)];
|
|
}
|
|
|
|
O2AffineTransform O2ContextGetTextRenderingMatrix(O2ContextRef self) {
|
|
O2GState *gState = O2ContextCurrentGState(self);
|
|
|
|
O2AffineTransform transformToDevice = gState->_deviceSpaceTransform;
|
|
O2AffineTransform Tm = self->_textMatrix;
|
|
|
|
return O2AffineTransformConcat(Tm, transformToDevice);
|
|
}
|
|
|
|
void O2ContextGetDefaultAdvances(O2ContextRef self, const O2Glyph *glyphs,
|
|
O2Size *advances, size_t count)
|
|
{
|
|
O2GState *gState = O2ContextCurrentGState(self);
|
|
O2Font *font = O2GStateFont(gState);
|
|
int intAdvances[count];
|
|
O2Float unitsPerEm = O2FontGetUnitsPerEm(font);
|
|
O2Float pointSize = O2GStatePointSize(gState);
|
|
size_t i;
|
|
|
|
O2FontGetGlyphAdvances(font, glyphs, count, intAdvances);
|
|
|
|
O2Float scale = [font nativeSizeForSize: pointSize] / unitsPerEm;
|
|
for (i = 0; i < count; i++) {
|
|
advances[i].width = intAdvances[i] * scale;
|
|
advances[i].height = 0;
|
|
}
|
|
}
|
|
|
|
void O2ContextConcatAdvancesToTextMatrix(O2ContextRef self,
|
|
const O2Size *advances, size_t count)
|
|
{
|
|
O2AffineTransform Tm = self->_textMatrix;
|
|
O2Size totalAdvance = O2SizeMake(0, 0);
|
|
size_t i;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
O2Size advance = O2SizeApplyAffineTransform(advances[i], Tm);
|
|
|
|
totalAdvance.width += advance.width;
|
|
totalAdvance.height += advance.height;
|
|
}
|
|
|
|
self->_textMatrix.tx += totalAdvance.width;
|
|
self->_textMatrix.ty += totalAdvance.height;
|
|
}
|
|
|
|
O2GState *O2ContextCurrentGState(O2ContextRef self) {
|
|
return self->_currentState;
|
|
}
|
|
|
|
// Temporary hacks
|
|
|
|
void O2ContextCopyBits(O2ContextRef self, O2Rect rect, O2Point point,
|
|
int gState)
|
|
{
|
|
if (self == nil)
|
|
return;
|
|
|
|
[self copyBitsInRect: rect toPoint: point gState: gState];
|
|
}
|
|
|
|
bool O2ContextSupportsGlobalAlpha(O2ContextRef self) {
|
|
return [self supportsGlobalAlpha];
|
|
}
|
|
|
|
NSData *O2ContextCaptureBitmap(O2ContextRef self, O2Rect rect) {
|
|
return [self captureBitmapInRect: rect];
|
|
}
|
|
|
|
bool O2ContextIsBitmapContext(O2ContextRef self) {
|
|
return [self isBitmapContext];
|
|
}
|
|
|
|
void O2ContextSetAllowsFontSmoothing(O2ContextRef self,
|
|
BOOL allowsFontSmoothing)
|
|
{
|
|
self->_allowsFontSmoothing = allowsFontSmoothing;
|
|
}
|
|
|
|
void O2ContextSetAllowsFontSubpixelQuantization(
|
|
O2ContextRef self, BOOL allowsFontSubpixelQuantization)
|
|
{
|
|
self->_allowsFontSubpixelQuantization = allowsFontSubpixelQuantization;
|
|
}
|
|
|
|
void O2ContextSetShouldSubpixelQuantizeFonts(O2ContextRef self,
|
|
BOOL shouldSubpixelQuantizeFonts)
|
|
{
|
|
self->_shouldSubpixelQuantizeFonts = shouldSubpixelQuantizeFonts;
|
|
}
|
|
|
|
void O2ContextSetAllowsFontSubpixelPositioning(
|
|
O2ContextRef self, BOOL allowsFontSubpixelPositioning)
|
|
{
|
|
self->_allowsFontSubpixelPositioning = allowsFontSubpixelPositioning;
|
|
}
|
|
|
|
void O2ContextSetShouldSubpixelPositionFonts(O2ContextRef self,
|
|
BOOL shouldSubpixelPositionFonts)
|
|
{
|
|
self->_shouldSubpixelPositionFonts = shouldSubpixelPositionFonts;
|
|
}
|
|
|
|
@end
|