mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-31 20:37:36 +00:00
Merge remote-tracking branch 'upstream/main' into Aristo3
This commit is contained in:
commit
1d1b41db83
4 files changed
+1015
-926
No files matched your search
@@ -21,38 +21,54 @@
|
||||
*/
|
||||
|
||||
@import "CGGeometry.j"
|
||||
// REMOVED: @import "CPCompatibility.j" - Obsolete legacy compatibility layer removed.
|
||||
@import "CPCompatibility.j"
|
||||
|
||||
#define PIXEL(pixels) pixels + "px";
|
||||
|
||||
// REMOVED: #define PIXEL(pixels) macro - Eliminated in favour of native inline string concatenation.
|
||||
|
||||
function CABackingStoreGetContext(aBackingStore)
|
||||
{
|
||||
return aBackingStore.context;
|
||||
}
|
||||
return aBackingStore.context;
|
||||
};
|
||||
|
||||
// REMOVED: if (CPFeatureIsCompatible(CPHTMLCanvasFeature)) - HTMLCanvasElement is natively supported across modern targets. Legacy fallback block completely removed.
|
||||
function CABackingStoreCreate()
|
||||
if (CPFeatureIsCompatible(CPHTMLCanvasFeature))
|
||||
{
|
||||
// MODERNIZED: Replaced legacy 'var' with block-scoped 'const' for immutable DOM reference.
|
||||
const DOMElement = document.createElement("canvas");
|
||||
|
||||
DOMElement.style.position = "absolute";
|
||||
|
||||
// FIXME: Consolidate drawImage to support this.
|
||||
return { context:DOMElement.getContext("2d"), buffer:DOMElement, _image:DOMElement };
|
||||
}
|
||||
|
||||
function CABackingStoreSetSize(aBackingStore, aSize)
|
||||
CABackingStoreCreate = function()
|
||||
{
|
||||
// MODERNIZED: Replaced legacy 'var' with block-scoped 'const'.
|
||||
const buffer = aBackingStore.buffer;
|
||||
var DOMElement = document.createElement("canvas");
|
||||
|
||||
buffer.width = aSize.width;
|
||||
buffer.height = aSize.height;
|
||||
DOMElement.style.position = "absolute";
|
||||
|
||||
// FIXME: Consolidate drawImage to support this.
|
||||
return { context:DOMElement.getContext("2d"), buffer:DOMElement, _image:DOMElement };
|
||||
};
|
||||
|
||||
CABackingStoreSetSize = function(aBackingStore, aSize)
|
||||
{
|
||||
var buffer = aBackingStore.buffer;
|
||||
|
||||
buffer.width = aSize.width;
|
||||
buffer.height = aSize.height;
|
||||
buffer.style.width = PIXEL(aSize.width);
|
||||
buffer.style.height = PIXEL(aSize.height);
|
||||
};
|
||||
|
||||
// MODERNIZED: Replaced macro expansion with native inline evaluation.
|
||||
buffer.style.width = aSize.width + "px";
|
||||
buffer.style.height = aSize.height + "px";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// REMOVED: Legacy else block utilizing CGBitmapGraphicsContextCreate due to guaranteed canvas support.
|
||||
CABackingStoreCreate = function()
|
||||
{
|
||||
var context = CGBitmapGraphicsContextCreate();
|
||||
|
||||
context.buffer = "";
|
||||
|
||||
return { context:context };
|
||||
};
|
||||
|
||||
CABackingStoreSetSize = function(aBackingStore, aSize)
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
+273
-280
File diff suppressed because it is too large.
Load diff
@@ -3,7 +3,6 @@
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Modified by David Richardson.
|
||||
* Copyright 2008, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@@ -21,518 +20,616 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
// MODIFICATION: Converted 'var' to 'const' for immutable lookup tables.
|
||||
const CANVAS_LINECAP_TABLE = [ "butt", "round", "square" ];
|
||||
const CANVAS_LINEJOIN_TABLE = [ "miter", "round", "bevel" ];
|
||||
const CANVAS_COMPOSITE_TABLE = [ "source-over", "source-over", "source-over", "source-over", "darker",
|
||||
"lighter", "source-over", "source-over", "source-over", "source-over",
|
||||
"source-over", "source-over", "source-over", "source-over", "source-over",
|
||||
"source-over", "source-over",
|
||||
"copy", "source-in", "source-out", "source-atop",
|
||||
"destination-over", "destination-in", "destination-out", "destination-atop",
|
||||
"xor", "source-over", "source-over" ];
|
||||
var CANVAS_LINECAP_TABLE = [ "butt", "round", "square" ],
|
||||
CANVAS_LINEJOIN_TABLE = [ "miter", "round", "bevel" ],
|
||||
CANVAS_COMPOSITE_TABLE = [ "source-over", "source-over", "source-over", "source-over", "darker",
|
||||
"lighter", "source-over", "source-over", "source-over", "source-over",
|
||||
"source-over", "source-over", "source-over", "source-over", "source-over",
|
||||
"source-over", "source-over",
|
||||
"copy", "source-in", "source-out", "source-atop",
|
||||
"destination-over", "destination-in", "destination-out", "destination-atop",
|
||||
"xor", "source-over", "source-over" ];
|
||||
|
||||
// MODIFICATION: Removed all #define macros. Canvas methods are now invoked directly within the target functions
|
||||
// to eliminate the preprocessor pass and simplify AST generation.
|
||||
#define _CGContextAddArcCanvas(aContext, x, y, radius, startAngle, endAngle, anticlockwise) aContext.arc(x, y, radius, startAngle, endAngle, anticlockwise)
|
||||
#define _CGContextAddArcToPointCanvas(aContext, x1, y1, x2, y2, radius) aContext.arcTo(x1, y1, x2, y2, radius)
|
||||
#define _CGContextAddCurveToPointCanvas(aContext, cp1x, cp1y, cp2x, cp2y, x, y) aContext.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
|
||||
#define _CGContextAddQuadCurveToPointCanvas(aContext, cpx, cpy, x, y) aContext.quadraticCurveTo(cpx, cpy, x, y)
|
||||
#define _CGContextAddLineToPointCanvas(aContext, x, y) aContext.lineTo(x, y)
|
||||
#define _CGContextClosePathCanvas(aContext) aContext.closePath()
|
||||
#define _CGContextMoveToPointCanvas(aContext, x, y) aContext.moveTo(x, y)
|
||||
|
||||
#define _CGContextAddRectCanvas(aContext, aRect) aContext.rect(CGRectGetMinX(aRect), CGRectGetMinY(aRect), CGRectGetWidth(aRect), CGRectGetHeight(aRect))
|
||||
#define _CGContextBeginPathCanvas(aContext) aContext.beginPath()
|
||||
#define _CGContextFillRectCanvas(aContext, aRect) aContext.fillRect(CGRectGetMinX(aRect), CGRectGetMinY(aRect), CGRectGetWidth(aRect), CGRectGetHeight(aRect))
|
||||
#define _CGContextClipCanvas(aContext) aContext.clip()
|
||||
|
||||
// In Cocoa, all primitives excepts rects and arcs cannot be added to the context's path
|
||||
// until a move to point has been done, because an empty path has no current point.
|
||||
// MODIFICATION: Converted to const function expression and applied Allman formatting.
|
||||
const hasPath = function(aContext, methodName)
|
||||
var hasPath = function(aContext, methodName)
|
||||
{
|
||||
if (!aContext.hasPath)
|
||||
{
|
||||
CPLog.error(methodName + ": no current point");
|
||||
}
|
||||
if (!aContext.hasPath)
|
||||
CPLog.error(methodName + ": no current point");
|
||||
|
||||
return aContext.hasPath;
|
||||
};
|
||||
return aContext.hasPath;
|
||||
}
|
||||
|
||||
function CGContextSaveGState(aContext)
|
||||
{
|
||||
aContext.save();
|
||||
aContext.save();
|
||||
}
|
||||
|
||||
function CGContextRestoreGState(aContext)
|
||||
{
|
||||
aContext.restore();
|
||||
aContext.restore();
|
||||
}
|
||||
|
||||
function CGContextSetLineCap(aContext, aLineCap)
|
||||
{
|
||||
aContext.lineCap = CANVAS_LINECAP_TABLE[aLineCap];
|
||||
aContext.lineCap = CANVAS_LINECAP_TABLE[aLineCap];
|
||||
}
|
||||
|
||||
function CGContextSetLineDash(aContext, aPhase, someDashes)
|
||||
{
|
||||
// MODIFICATION: Removed obsolete vendor prefixes (webkitLineDash, mozDash).
|
||||
if (aContext.setLineDash)
|
||||
{
|
||||
aContext.setLineDash(someDashes);
|
||||
aContext.lineDashOffset = aPhase;
|
||||
}
|
||||
else if (someDashes)
|
||||
{
|
||||
CPLog.warn("CGContextSetLineDash not implemented in this environment.");
|
||||
}
|
||||
if (aContext.setLineDash)
|
||||
{
|
||||
aContext.setLineDash(someDashes);
|
||||
aContext.lineDashOffset = aPhase;
|
||||
}
|
||||
else if (typeof aContext['webkitLineDash'] !== 'undefined')
|
||||
{
|
||||
aContext.webkitLineDash = someDashes;
|
||||
aContext.webkitLineDashOffset = aPhase;
|
||||
}
|
||||
else if (typeof aContext['mozDash'] !== 'undefined')
|
||||
{
|
||||
aContext.mozDash = someDashes;
|
||||
aContext.mozDashOffset = aPhase;
|
||||
}
|
||||
else if (someDashes)
|
||||
{
|
||||
CPLog.warn("CGContextSetLineDash not implemented in this environment.")
|
||||
}
|
||||
}
|
||||
|
||||
function CGContextSetLineJoin(aContext, aLineJoin)
|
||||
{
|
||||
aContext.lineJoin = CANVAS_LINEJOIN_TABLE[aLineJoin];
|
||||
aContext.lineJoin = CANVAS_LINEJOIN_TABLE[aLineJoin];
|
||||
}
|
||||
|
||||
function CGContextSetLineWidth(aContext, aLineWidth)
|
||||
{
|
||||
aContext.lineWidth = aLineWidth;
|
||||
aContext.lineWidth = aLineWidth;
|
||||
}
|
||||
|
||||
function CGContextSetMiterLimit(aContext, aMiterLimit)
|
||||
{
|
||||
aContext.miterLimit = aMiterLimit;
|
||||
aContext.miterLimit = aMiterLimit;
|
||||
}
|
||||
|
||||
function CGContextSetBlendMode(aContext, aBlendMode)
|
||||
{
|
||||
aContext.globalCompositeOperation = CANVAS_COMPOSITE_TABLE[aBlendMode];
|
||||
aContext.globalCompositeOperation = CANVAS_COMPOSITE_TABLE[aBlendMode];
|
||||
}
|
||||
|
||||
function CGContextAddArc(aContext, x, y, radius, startAngle, endAngle, clockwise)
|
||||
{
|
||||
// Despite the documentation saying otherwise, the last parameter is anti-clockwise not clockwise.
|
||||
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes#Arcs
|
||||
// MODIFICATION: Direct invocation replacing _CGContextAddArcCanvas macro.
|
||||
aContext.arc(x, y, radius, startAngle, endAngle, !clockwise);
|
||||
// Despite the documentation saying otherwise, the last parameter is anti-clockwise not clockwise.
|
||||
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes#Arcs
|
||||
_CGContextAddArcCanvas(aContext, x, y, radius, startAngle, endAngle, !clockwise);
|
||||
|
||||
// AddArc implicitly starts a path
|
||||
aContext.hasPath = YES;
|
||||
// AddArc implicitly starts a path
|
||||
aContext.hasPath = YES;
|
||||
}
|
||||
|
||||
function CGContextAddArcToPoint(aContext, x1, y1, x2, y2, radius)
|
||||
{
|
||||
if (!hasPath(aContext, "CGContextAddArcToPoint"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!hasPath(aContext, "CGContextAddArcToPoint"))
|
||||
return;
|
||||
|
||||
// MODIFICATION: Direct invocation replacing _CGContextAddArcToPointCanvas macro.
|
||||
aContext.arcTo(x1, y1, x2, y2, radius);
|
||||
_CGContextAddArcToPointCanvas(aContext, x1, y1, x2, y2, radius);
|
||||
}
|
||||
|
||||
function CGContextAddCurveToPoint(aContext, cp1x, cp1y, cp2x, cp2y, x, y)
|
||||
{
|
||||
if (!hasPath(aContext, "CGContextAddCurveToPoint"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!hasPath(aContext, "CGContextAddCurveToPoint"))
|
||||
return;
|
||||
|
||||
// MODIFICATION: Direct invocation replacing _CGContextAddCurveToPointCanvas macro.
|
||||
aContext.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
|
||||
_CGContextAddCurveToPointCanvas(aContext, cp1x, cp1y, cp2x, cp2y, x, y);
|
||||
}
|
||||
|
||||
function CGContextAddLines(aContext, points, count)
|
||||
{
|
||||
// implementation mirrors that of CGPathAddLines()
|
||||
if (count == null)
|
||||
{
|
||||
count = points.length;
|
||||
}
|
||||
// implementation mirrors that of CGPathAddLines()
|
||||
if (count == null)
|
||||
count = points.length;
|
||||
|
||||
if (count < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (count < 1)
|
||||
return;
|
||||
|
||||
// MODIFICATION: Direct invocations replacing macros.
|
||||
aContext.moveTo(points[0].x, points[0].y);
|
||||
_CGContextMoveToPointCanvas(aContext, points[0].x, points[0].y);
|
||||
|
||||
// MODIFICATION: Replaced 'var' with 'let'.
|
||||
for (let i = 1; i < count; ++i)
|
||||
{
|
||||
aContext.lineTo(points[i].x, points[i].y);
|
||||
}
|
||||
for (var i = 1; i < count; ++i)
|
||||
_CGContextAddLineToPointCanvas(aContext, points[i].x, points[i].y);
|
||||
|
||||
aContext.hasPath = YES;
|
||||
aContext.hasPath = YES;
|
||||
}
|
||||
|
||||
function CGContextAddLineToPoint(aContext, x, y)
|
||||
{
|
||||
if (!hasPath(aContext, "CGContextAddLineToPoint"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!hasPath(aContext, "CGContextAddLineToPoint"))
|
||||
return;
|
||||
|
||||
// MODIFICATION: Direct invocation replacing macro.
|
||||
aContext.lineTo(x, y);
|
||||
_CGContextAddLineToPointCanvas(aContext, x, y);
|
||||
}
|
||||
|
||||
function CGContextAddPath(aContext, aPath)
|
||||
{
|
||||
if (!aContext || CGPathIsEmpty(aPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!aContext || CGPathIsEmpty(aPath))
|
||||
return;
|
||||
|
||||
// If the context does not have a path, explicitly begin one
|
||||
if (!aContext.hasPath)
|
||||
{
|
||||
aContext.beginPath();
|
||||
}
|
||||
// If the context does not have a path, explicitly begin one
|
||||
if (!aContext.hasPath)
|
||||
_CGContextBeginPathCanvas(aContext);
|
||||
|
||||
// We must implicitly move to the start of the path
|
||||
aContext.moveTo(aPath.start.x, aPath.start.y);
|
||||
// We must implicitly move to the start of the path
|
||||
_CGContextMoveToPointCanvas(aContext, aPath.start.x, aPath.start.y);
|
||||
|
||||
// MODIFICATION: Replaced 'var' with 'const'/'let'.
|
||||
const elements = aPath.elements,
|
||||
count = aPath.count;
|
||||
var elements = aPath.elements,
|
||||
i = 0,
|
||||
count = aPath.count;
|
||||
|
||||
for (let i = 0; i < count; ++i)
|
||||
{
|
||||
const element = elements[i],
|
||||
type = element.type;
|
||||
for (; i < count; ++i)
|
||||
{
|
||||
var element = elements[i],
|
||||
type = element.type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case kCGPathElementMoveToPoint:
|
||||
aContext.moveTo(element.x, element.y);
|
||||
break;
|
||||
switch (type)
|
||||
{
|
||||
case kCGPathElementMoveToPoint:
|
||||
_CGContextMoveToPointCanvas(aContext, element.x, element.y);
|
||||
break;
|
||||
|
||||
case kCGPathElementAddLineToPoint:
|
||||
aContext.lineTo(element.x, element.y);
|
||||
break;
|
||||
case kCGPathElementAddLineToPoint:
|
||||
_CGContextAddLineToPointCanvas(aContext, element.x, element.y);
|
||||
break;
|
||||
|
||||
case kCGPathElementAddQuadCurveToPoint:
|
||||
aContext.quadraticCurveTo(element.cpx, element.cpy, element.x, element.y);
|
||||
break;
|
||||
case kCGPathElementAddQuadCurveToPoint:
|
||||
_CGContextAddQuadCurveToPointCanvas(aContext, element.cpx, element.cpy, element.x, element.y);
|
||||
break;
|
||||
|
||||
case kCGPathElementAddCurveToPoint:
|
||||
aContext.bezierCurveTo(element.cp1x, element.cp1y, element.cp2x, element.cp2y, element.x, element.y);
|
||||
break;
|
||||
case kCGPathElementAddCurveToPoint:
|
||||
_CGContextAddCurveToPointCanvas(aContext, element.cp1x, element.cp1y, element.cp2x, element.cp2y, element.x, element.y);
|
||||
break;
|
||||
|
||||
case kCGPathElementCloseSubpath:
|
||||
aContext.closePath();
|
||||
break;
|
||||
case kCGPathElementCloseSubpath:
|
||||
_CGContextClosePathCanvas(aContext);
|
||||
break;
|
||||
|
||||
case kCGPathElementAddArc:
|
||||
aContext.arc(element.x, element.y, element.radius, element.startAngle, element.endAngle, element.clockwise);
|
||||
break;
|
||||
case kCGPathElementAddArc:
|
||||
_CGContextAddArcCanvas(aContext, element.x, element.y, element.radius, element.startAngle, element.endAngle, element.clockwise);
|
||||
break;
|
||||
|
||||
case kCGPathElementAddArcToPoint:
|
||||
aContext.arcTo(element.p1x, element.p1y, element.p2x, element.p2y, element.radius);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case kCGPathElementAddArcToPoint:
|
||||
_CGContextAddArcToPointCanvas(aContext, element.p1x, element.p1y, element.p2x, element.p2y, element.radius);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
aContext.hasPath = YES;
|
||||
aContext.hasPath = YES;
|
||||
}
|
||||
|
||||
function CGContextAddRect(aContext, aRect)
|
||||
{
|
||||
// MODIFICATION: Direct invocation replacing _CGContextAddRectCanvas macro.
|
||||
aContext.rect(CGRectGetMinX(aRect), CGRectGetMinY(aRect), CGRectGetWidth(aRect), CGRectGetHeight(aRect));
|
||||
aContext.hasPath = YES;
|
||||
_CGContextAddRectCanvas(aContext, aRect);
|
||||
aContext.hasPath = YES;
|
||||
}
|
||||
|
||||
function CGContextAddQuadCurveToPoint(aContext, cpx, cpy, x, y)
|
||||
{
|
||||
if (!hasPath(aContext, "CGContextAddQuadCurveToPoint"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!hasPath(aContext, "CGContextAddQuadCurveToPoint"))
|
||||
return;
|
||||
|
||||
// MODIFICATION: Direct invocation replacing macro.
|
||||
aContext.quadraticCurveTo(cpx, cpy, x, y);
|
||||
_CGContextAddQuadCurveToPointCanvas(aContext, cpx, cpy, x, y);
|
||||
}
|
||||
|
||||
function CGContextAddRects(aContext, rects, count)
|
||||
{
|
||||
if (count == null)
|
||||
{
|
||||
count = rects.length;
|
||||
}
|
||||
if (count == null)
|
||||
count = rects.length;
|
||||
|
||||
for (let i = 0; i < count; ++i)
|
||||
{
|
||||
const rect = rects[i];
|
||||
aContext.rect(CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetWidth(rect), CGRectGetHeight(rect));
|
||||
}
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
var rect = rects[i];
|
||||
_CGContextAddRectCanvas(aContext, rect);
|
||||
}
|
||||
|
||||
aContext.hasPath = YES;
|
||||
aContext.hasPath = YES;
|
||||
}
|
||||
|
||||
function CGContextBeginPath(aContext)
|
||||
{
|
||||
aContext.beginPath();
|
||||
aContext.hasPath = NO;
|
||||
_CGContextBeginPathCanvas(aContext);
|
||||
aContext.hasPath = NO;
|
||||
}
|
||||
|
||||
function CGContextClosePath(aContext)
|
||||
{
|
||||
aContext.closePath();
|
||||
_CGContextClosePathCanvas(aContext);
|
||||
}
|
||||
|
||||
function CGContextIsPathEmpty(aContext)
|
||||
{
|
||||
return !aContext.hasPath;
|
||||
return !aContext.hasPath;
|
||||
}
|
||||
|
||||
function CGContextMoveToPoint(aContext, x, y)
|
||||
{
|
||||
aContext.moveTo(x, y);
|
||||
aContext.hasPath = YES;
|
||||
_CGContextMoveToPointCanvas(aContext, x, y);
|
||||
aContext.hasPath = YES;
|
||||
}
|
||||
|
||||
function CGContextClearRect(aContext, aRect)
|
||||
{
|
||||
aContext.clearRect(CGRectGetMinX(aRect), CGRectGetMinY(aRect), CGRectGetWidth(aRect), CGRectGetHeight(aRect));
|
||||
aContext.hasPath = NO;
|
||||
aContext.clearRect(CGRectGetMinX(aRect), CGRectGetMinY(aRect), CGRectGetWidth(aRect), CGRectGetHeight(aRect));
|
||||
aContext.hasPath = NO;
|
||||
}
|
||||
|
||||
function CGContextDrawPath(aContext, aMode)
|
||||
{
|
||||
if (!aContext.hasPath)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!aContext.hasPath)
|
||||
return;
|
||||
|
||||
if (aMode === kCGPathFill || aMode === kCGPathFillStroke)
|
||||
{
|
||||
aContext.fill();
|
||||
}
|
||||
else if (aMode === kCGPathStroke || aMode === kCGPathFillStroke || aMode === kCGPathEOFillStroke)
|
||||
{
|
||||
aContext.stroke();
|
||||
}
|
||||
else if (aMode === kCGPathEOFill || aMode === kCGPathEOFillStroke)
|
||||
{
|
||||
CPLog.warn("Unimplemented fill mode in CGContextDrawPath: %d", aMode);
|
||||
}
|
||||
if (aMode === kCGPathFill || aMode === kCGPathFillStroke)
|
||||
aContext.fill();
|
||||
else if (aMode === kCGPathStroke || aMode === kCGPathFillStroke || aMode === kCGPathEOFillStroke)
|
||||
aContext.stroke();
|
||||
else if (aMode === kCGPathEOFill || aMode === kCGPathEOFillStroke)
|
||||
CPLog.warn("Unimplemented fill mode in CGContextDrawPath: %d", aMode);
|
||||
|
||||
aContext.hasPath = NO;
|
||||
aContext.hasPath = NO;
|
||||
}
|
||||
|
||||
function CGContextFillRect(aContext, aRect)
|
||||
{
|
||||
// MODIFICATION: Direct invocation replacing macro.
|
||||
aContext.fillRect(CGRectGetMinX(aRect), CGRectGetMinY(aRect), CGRectGetWidth(aRect), CGRectGetHeight(aRect));
|
||||
aContext.hasPath = NO;
|
||||
_CGContextFillRectCanvas(aContext, aRect);
|
||||
aContext.hasPath = NO;
|
||||
}
|
||||
|
||||
function CGContextFillRects(aContext, rects, count)
|
||||
{
|
||||
if (count == null)
|
||||
{
|
||||
count = rects.length;
|
||||
}
|
||||
if (count == null)
|
||||
count = rects.length;
|
||||
|
||||
for (let i = 0; i < count; ++i)
|
||||
{
|
||||
const rect = rects[i];
|
||||
aContext.fillRect(CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetWidth(rect), CGRectGetHeight(rect));
|
||||
}
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
var rect = rects[i];
|
||||
_CGContextFillRectCanvas(aContext, rect);
|
||||
}
|
||||
|
||||
aContext.hasPath = NO;
|
||||
aContext.hasPath = NO;
|
||||
}
|
||||
|
||||
function CGContextStrokeRect(aContext, aRect)
|
||||
{
|
||||
aContext.strokeRect(CGRectGetMinX(aRect), CGRectGetMinY(aRect), CGRectGetWidth(aRect), CGRectGetHeight(aRect));
|
||||
aContext.hasPath = NO;
|
||||
aContext.strokeRect(CGRectGetMinX(aRect), CGRectGetMinY(aRect), CGRectGetWidth(aRect), CGRectGetHeight(aRect));
|
||||
aContext.hasPath = NO;
|
||||
}
|
||||
|
||||
function CGContextClip(aContext)
|
||||
{
|
||||
aContext.clip();
|
||||
aContext.hasPath = NO;
|
||||
_CGContextClipCanvas(aContext);
|
||||
aContext.hasPath = NO;
|
||||
}
|
||||
|
||||
function CGContextClipToRect(aContext, aRect)
|
||||
{
|
||||
aContext.beginPath();
|
||||
aContext.rect(CGRectGetMinX(aRect), CGRectGetMinY(aRect), CGRectGetWidth(aRect), CGRectGetHeight(aRect));
|
||||
aContext.closePath();
|
||||
_CGContextBeginPathCanvas(aContext);
|
||||
_CGContextAddRectCanvas(aContext, aRect);
|
||||
_CGContextClosePathCanvas(aContext);
|
||||
|
||||
aContext.clip();
|
||||
aContext.hasPath = NO;
|
||||
_CGContextClipCanvas(aContext);
|
||||
aContext.hasPath = NO;
|
||||
}
|
||||
|
||||
function CGContextClipToRects(aContext, rects, count)
|
||||
{
|
||||
if (count == null)
|
||||
{
|
||||
count = rects.length;
|
||||
}
|
||||
if (count == null)
|
||||
count = rects.length;
|
||||
|
||||
aContext.beginPath();
|
||||
CGContextAddRects(aContext, rects, count);
|
||||
aContext.clip();
|
||||
aContext.hasPath = NO;
|
||||
_CGContextBeginPathCanvas(aContext);
|
||||
CGContextAddRects(aContext, rects, count);
|
||||
_CGContextClipCanvas(aContext);
|
||||
aContext.hasPath = NO;
|
||||
}
|
||||
|
||||
function CGContextSetAlpha(aContext, anAlpha)
|
||||
{
|
||||
aContext.globalAlpha = anAlpha;
|
||||
aContext.globalAlpha = anAlpha;
|
||||
}
|
||||
|
||||
function CGContextSetFillColor(aContext, aColor)
|
||||
{
|
||||
const patternImage = [aColor patternImage];
|
||||
var patternImage = [aColor patternImage];
|
||||
|
||||
if ([patternImage isSingleImage])
|
||||
{
|
||||
const pattern = aContext.createPattern([patternImage image], "repeat");
|
||||
aContext.fillStyle = pattern;
|
||||
}
|
||||
else
|
||||
{
|
||||
aContext.fillStyle = [aColor cssString];
|
||||
}
|
||||
if ([patternImage isSingleImage])
|
||||
{
|
||||
var pattern = aContext.createPattern([patternImage image], "repeat");
|
||||
|
||||
aContext.fillStyle = pattern;
|
||||
}
|
||||
else
|
||||
aContext.fillStyle = [aColor cssString];
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a context into which you can render a fill pattern
|
||||
of the given size. Once the pattern is rendered, you can
|
||||
set the fill or stroke pattern to the rendered pattern
|
||||
with CGContextSetFillPattern or CGContextSetStrokePattern.
|
||||
*/
|
||||
Creates a context into which you can render a fill pattern
|
||||
of the given size. Once the pattern is rendered, you can
|
||||
set the fill or stroke pattern to the rendered pattern
|
||||
with CGContextSetFillPattern or CGContextSetStrokePattern.
|
||||
*/
|
||||
function CGContextCreatePatternContext(aContext, aSize)
|
||||
{
|
||||
const pattern = document.createElement("canvas");
|
||||
var pattern = document.createElement("canvas");
|
||||
|
||||
pattern.width = aSize.width;
|
||||
pattern.height = aSize.height;
|
||||
pattern.width = aSize.width;
|
||||
pattern.height = aSize.height;
|
||||
|
||||
return pattern.getContext("2d");
|
||||
return pattern.getContext("2d");
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the fill pattern for aContext to the rendered pattern context
|
||||
returned by CGContextCreatePatternContext.
|
||||
*/
|
||||
Sets the fill pattern for aContext to the rendered pattern context
|
||||
returned by CGContextCreatePatternContext.
|
||||
*/
|
||||
function CGContextSetFillPattern(aContext, aPatternContext)
|
||||
{
|
||||
const pattern = aContext.createPattern(aPatternContext.canvas, "repeat");
|
||||
aContext.fillStyle = pattern;
|
||||
var pattern = aContext.createPattern(aPatternContext.canvas, "repeat");
|
||||
aContext.fillStyle = pattern;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the stroke pattern for aContext to the rendered pattern context
|
||||
returned by CGContextCreatePatternContext.
|
||||
*/
|
||||
Sets the stroke pattern for aContext to the rendered pattern context
|
||||
returned by CGContextCreatePatternContext.
|
||||
*/
|
||||
function CGContextSetStrokePattern(aContext, aPatternContext)
|
||||
{
|
||||
const pattern = aContext.createPattern(aPatternContext.canvas, "repeat");
|
||||
aContext.strokeStyle = pattern;
|
||||
var pattern = aContext.createPattern(aPatternContext.canvas, "repeat");
|
||||
aContext.strokeStyle = pattern;
|
||||
}
|
||||
|
||||
function CGContextSetStrokeColor(aContext, aColor)
|
||||
{
|
||||
const patternImage = [aColor patternImage];
|
||||
var patternImage = [aColor patternImage];
|
||||
|
||||
if ([patternImage isSingleImage])
|
||||
{
|
||||
const pattern = aContext.createPattern([patternImage image], "repeat");
|
||||
aContext.strokeStyle = pattern;
|
||||
}
|
||||
else
|
||||
{
|
||||
aContext.strokeStyle = [aColor cssString];
|
||||
}
|
||||
if ([patternImage isSingleImage])
|
||||
{
|
||||
var pattern = aContext.createPattern([patternImage image], "repeat");
|
||||
|
||||
aContext.strokeStyle = pattern;
|
||||
}
|
||||
else
|
||||
aContext.strokeStyle = [aColor cssString];
|
||||
}
|
||||
|
||||
function CGContextSetShadow(aContext, aSize, aBlur)
|
||||
{
|
||||
aContext.shadowOffsetX = aSize.width;
|
||||
aContext.shadowOffsetY = aSize.height;
|
||||
aContext.shadowBlur = aBlur;
|
||||
aContext.shadowColor = [[CPColor shadowColor] cssString];
|
||||
aContext.shadowOffsetX = aSize.width;
|
||||
aContext.shadowOffsetY = aSize.height;
|
||||
aContext.shadowBlur = aBlur;
|
||||
aContext.shadowColor = [[CPColor shadowColor] cssString];
|
||||
}
|
||||
|
||||
function CGContextSetShadowWithColor(aContext, aSize, aBlur, aColor)
|
||||
{
|
||||
aContext.shadowOffsetX = aSize.width;
|
||||
aContext.shadowOffsetY = aSize.height;
|
||||
aContext.shadowBlur = aBlur;
|
||||
aContext.shadowColor = [aColor cssString];
|
||||
aContext.shadowOffsetX = aSize.width;
|
||||
aContext.shadowOffsetY = aSize.height;
|
||||
aContext.shadowBlur = aBlur;
|
||||
aContext.shadowColor = [aColor cssString];
|
||||
}
|
||||
|
||||
function CGContextRotateCTM(aContext, anAngle)
|
||||
{
|
||||
aContext.rotate(anAngle);
|
||||
aContext.rotate(anAngle);
|
||||
}
|
||||
|
||||
function CGContextScaleCTM(aContext, sx, sy)
|
||||
{
|
||||
aContext.scale(sx, sy);
|
||||
aContext.scale(sx, sy);
|
||||
}
|
||||
|
||||
function CGContextTranslateCTM(aContext, tx, ty)
|
||||
{
|
||||
aContext.translate(tx, ty);
|
||||
aContext.translate(tx, ty);
|
||||
}
|
||||
|
||||
// MODIFICATION: Removed legacy mathematical fallback macros (scale_rotate, rotate_scale, eigen).
|
||||
// MODIFICATION: Removed CPFeatureIsCompatible(CPJavaScriptCanvasTransformFeature) branch.
|
||||
// Modern target environments inherently support native canvas transformations.
|
||||
|
||||
function CGContextConcatCTM(aContext, anAffineTransform)
|
||||
var scale_rotate = function(a, b, c, d)
|
||||
{
|
||||
aContext.transform(anAffineTransform.a, anAffineTransform.b, anAffineTransform.c, anAffineTransform.d, anAffineTransform.tx, anAffineTransform.ty);
|
||||
var sign = (a * d < 0.0 || b * c > 0.0) ? -1.0 : 1.0,
|
||||
a2 = (ATAN2(b, d) + ATAN2(-sign * c, sign * a)) / 2.0,
|
||||
cos = COS(a2),
|
||||
sin = SIN(a2);
|
||||
|
||||
if (cos === 0)
|
||||
{
|
||||
sx = -c / sin;
|
||||
sy = b / sin;
|
||||
}
|
||||
else if (sin === 0)
|
||||
{
|
||||
sx = a / cos;
|
||||
sy = d / cos;
|
||||
}
|
||||
else
|
||||
{
|
||||
abs_cos = ABS(cos);
|
||||
abs_sin = ABS(sin);
|
||||
|
||||
sx = (abs_cos * a / cos + abs_sin * -c / sin) / (abs_cos + abs_sin);
|
||||
sy = (abs_cos * d / cos + abs_sin * b / sin) / (abs_cos + abs_sin);
|
||||
}
|
||||
};
|
||||
|
||||
var rotate_scale = function(a, b, c, d)
|
||||
{
|
||||
var sign = (a * d < 0.0 || b * c > 0.0) ? -1.0 : 1.0,
|
||||
a1 = (ATAN2(sign * b, sign * a) + ATAN2(-c, d)) / 2.0,
|
||||
cos = COS(a1),
|
||||
sin = SIN(a1);
|
||||
|
||||
if (cos === 0)
|
||||
{
|
||||
sx = b / sin;
|
||||
sy = -c / sin;
|
||||
}
|
||||
else if (sin === 0)
|
||||
{
|
||||
sx = a / cos;
|
||||
sy = d / cos;
|
||||
}
|
||||
else
|
||||
{
|
||||
abs_cos = ABS(cos);
|
||||
abs_sin = ABS(sin);
|
||||
|
||||
sx = (abs_cos * a / cos + abs_sin * b / sin) / (abs_cos + abs_sin);
|
||||
sy = (abs_cos * d / cos + abs_sin * -c / sin) / (abs_cos + abs_sin);
|
||||
}
|
||||
};
|
||||
|
||||
function eigen(anAffineTransform)
|
||||
{
|
||||
CPLog.warn("Unimplemented function: eigen");
|
||||
}
|
||||
|
||||
|
||||
if (CPFeatureIsCompatible(CPJavaScriptCanvasTransformFeature))
|
||||
{
|
||||
|
||||
CGContextConcatCTM = function(aContext, anAffineTransform)
|
||||
{
|
||||
aContext.transform(anAffineTransform.a, anAffineTransform.b, anAffineTransform.c, anAffineTransform.d, anAffineTransform.tx, anAffineTransform.ty);
|
||||
};
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
CGContextConcatCTM = function(aContext, anAffineTransform)
|
||||
{
|
||||
var a = anAffineTransform.a,
|
||||
b = anAffineTransform.b,
|
||||
c = anAffineTransform.c,
|
||||
d = anAffineTransform.d,
|
||||
tx = anAffineTransform.tx,
|
||||
ty = anAffineTransform.ty,
|
||||
sx = 1.0,
|
||||
sy = 1.0,
|
||||
a1 = 0.0,
|
||||
a2 = 0.0;
|
||||
|
||||
// Detect the simple case of just scaling.
|
||||
if (b === 0.0 && c === 0.0)
|
||||
{
|
||||
sx = a;
|
||||
sy = d;
|
||||
}
|
||||
|
||||
// a scale followed by a rotate
|
||||
else if (a * b === -c * d)
|
||||
{
|
||||
scale_rotate(a, b, c, d)
|
||||
}
|
||||
|
||||
// rotate, then scale.
|
||||
else if (a * c === -b * d)
|
||||
{
|
||||
rotate_scale(a, b, c, d)
|
||||
}
|
||||
else
|
||||
{
|
||||
var transpose = CGAffineTransformMake(a, c, b, d, 0.0, 0.0), // inline
|
||||
u = eigen(CGAffineTransformConcat(anAffineTransform, transpose)),
|
||||
v = eigen(CGAffineTransformConcat(transpose, anAffineTransform)),
|
||||
U = CGAffineTransformMake(u.vector_1.x, u.vector_2.x, u.vector_1.y, u.vector_2.y, 0.0, 0.0), // inline
|
||||
VT = CGAffineTransformMake(v.vector_1.x, v.vector_1.y, v.vector_2.x, v.vector_2.y, 0.0, 0.0),
|
||||
S = CGAffineTransformConcat(CGAffineTransformConcat(CGAffineTransformInvert(U), anAffineTransform), CGAffineTransformInvert(VT));
|
||||
|
||||
a = VT.a;
|
||||
b = VT.b;
|
||||
c = VT.c;
|
||||
d = VT.d;
|
||||
scale_rotate(a, b, c, d);
|
||||
S.a *= sx;
|
||||
S.d *= sy;
|
||||
a = U.a;
|
||||
b = U.b;
|
||||
c = U.c;
|
||||
d = U.d;
|
||||
rotate_scale(a, b, c, d);
|
||||
sx = S.a * sx;
|
||||
sy = S.d * sy;
|
||||
}
|
||||
|
||||
if (tx != 0 || ty != 0)
|
||||
CGContextTranslateCTM(aContext, tx, ty);
|
||||
if (a1 != 0.0)
|
||||
CGContextRotateCTM(aContext, a1);
|
||||
if (sx != 1.0 || sy != 1.0)
|
||||
CGContextScaleCTM(aContext, sx, sy);
|
||||
if (a2 != 0.0)
|
||||
CGContextRotateCTM(aContext, a2);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
function CGContextDrawImage(aContext, aRect, anImage)
|
||||
{
|
||||
aContext.drawImage(anImage._image, CGRectGetMinX(aRect), CGRectGetMinY(aRect), CGRectGetWidth(aRect), CGRectGetHeight(aRect));
|
||||
aContext.hasPath = NO;
|
||||
aContext.drawImage(anImage._image, CGRectGetMinX(aRect), CGRectGetMinY(aRect), CGRectGetWidth(aRect), CGRectGetHeight(aRect));
|
||||
aContext.hasPath = NO;
|
||||
}
|
||||
|
||||
function to_string(aColor)
|
||||
{
|
||||
// MODIFICATION: Replaced macro ROUND with standard Math.round.
|
||||
return "rgba(" + Math.round(aColor.components[0] * 255) + ", " + Math.round(aColor.components[1] * 255) + ", " + Math.round(255 * aColor.components[2]) + ", " + aColor.components[3] + ")";
|
||||
return "rgba(" + ROUND(aColor.components[0] * 255) + ", " + ROUND(aColor.components[1] * 255) + ", " + ROUND(255 * aColor.components[2]) + ", " + aColor.components[3] + ")";
|
||||
}
|
||||
|
||||
function CGContextDrawLinearGradient(aContext, aGradient, aStartPoint, anEndPoint, options)
|
||||
{
|
||||
const colors = aGradient.colors;
|
||||
const linearGradient = aContext.createLinearGradient(aStartPoint.x, aStartPoint.y, anEndPoint.x, anEndPoint.y);
|
||||
let count = colors.length;
|
||||
var colors = aGradient.colors,
|
||||
count = colors.length,
|
||||
linearGradient = aContext.createLinearGradient(aStartPoint.x, aStartPoint.y, anEndPoint.x, anEndPoint.y);
|
||||
|
||||
while (count--)
|
||||
{
|
||||
linearGradient.addColorStop(aGradient.locations[count], to_string(colors[count]));
|
||||
}
|
||||
while (count--)
|
||||
linearGradient.addColorStop(aGradient.locations[count], to_string(colors[count]));
|
||||
|
||||
aContext.fillStyle = linearGradient;
|
||||
aContext.fill();
|
||||
aContext.hasPath = NO;
|
||||
aContext.fillStyle = linearGradient;
|
||||
aContext.fill();
|
||||
aContext.hasPath = NO;
|
||||
}
|
||||
|
||||
function CGContextDrawRadialGradient(aContext, aGradient, aStartCenter, aStartRadius, anEndCenter, anEndRadius, options)
|
||||
{
|
||||
const colors = aGradient.colors;
|
||||
const linearGradient = aContext.createRadialGradient(aStartCenter.x, aStartCenter.y, aStartRadius, anEndCenter.x, anEndCenter.y, anEndRadius);
|
||||
let count = colors.length;
|
||||
var colors = aGradient.colors,
|
||||
count = colors.length,
|
||||
linearGradient = aContext.createRadialGradient(aStartCenter.x, aStartCenter.y, aStartRadius, anEndCenter.x, anEndCenter.y, anEndRadius);
|
||||
|
||||
while (count--)
|
||||
{
|
||||
linearGradient.addColorStop(aGradient.locations[count], to_string(colors[count]));
|
||||
}
|
||||
while (count--)
|
||||
linearGradient.addColorStop(aGradient.locations[count], to_string(colors[count]));
|
||||
|
||||
aContext.fillStyle = linearGradient;
|
||||
aContext.fill();
|
||||
aContext.hasPath = NO;
|
||||
aContext.fillStyle = linearGradient;
|
||||
aContext.fill();
|
||||
aContext.hasPath = NO;
|
||||
}
|
||||
|
||||
function CGBitmapGraphicsContextCreate()
|
||||
{
|
||||
const DOMElement = document.createElement("canvas");
|
||||
const context = DOMElement.getContext("2d");
|
||||
var DOMElement = document.createElement("canvas"),
|
||||
context = DOMElement.getContext("2d");
|
||||
|
||||
context.DOMElement = DOMElement;
|
||||
context.DOMElement = DOMElement;
|
||||
|
||||
// canvas gives us no way to query whether the path is empty or not, so we have to track it ourselves
|
||||
context.hasPath = NO;
|
||||
// canvas gives us no way to query whether the path is empty or not, so we have to track it ourselves
|
||||
context.hasPath = NO;
|
||||
|
||||
return context;
|
||||
return context;
|
||||
}
|
||||
@@ -37,24 +37,22 @@
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
// MODIFICATION: Removed #define macros for SUPPRESS_CAPPUCCINO_CUT/PASTE.
|
||||
// Property assignments are now inlined directly at call sites for readability.
|
||||
#define SUPPRESS_CAPPUCCINO_CUT_FOR_EVENT(anEvent) anEvent._suppressCappuccinoCut = YES
|
||||
#define SUPPRESS_CAPPUCCINO_PASTE_FOR_EVENT(anEvent) anEvent._suppressCappuccinoPaste = YES
|
||||
|
||||
var hasEditableTarget = function(aDOMEvent)
|
||||
{
|
||||
// MODIFICATION: Removed IE 'srcElement' fallback. Replaced 'var' with 'let'.
|
||||
let target = aDOMEvent.target;
|
||||
var target = aDOMEvent.target || aDOMEvent.srcElement;
|
||||
|
||||
if (!target)
|
||||
return NO;
|
||||
if (!target)
|
||||
return NO;
|
||||
|
||||
if (target.contentEditable == "true")
|
||||
return YES;
|
||||
if (target.contentEditable == "true")
|
||||
return YES;
|
||||
|
||||
// MODIFICATION: Replaced 'var' with 'let'.
|
||||
let nodeName = target.nodeName.toUpperCase();
|
||||
var nodeName = target.nodeName.toUpperCase();
|
||||
|
||||
return nodeName === "INPUT" || nodeName == "TEXTAREA";
|
||||
return nodeName === "INPUT" || nodeName == "TEXTAREA";
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -65,481 +63,466 @@ var hasEditableTarget = function(aDOMEvent)
|
||||
*/
|
||||
@implementation CPPlatformPasteboard : CPObject
|
||||
{
|
||||
DOMWindow _DOMWindow;
|
||||
DOMWindow _DOMWindow;
|
||||
|
||||
DOMElement _DOMPasteboardElement;
|
||||
DOMElement _DOMPasteboardElement;
|
||||
|
||||
BOOL supportsNativeCopyAndPaste;
|
||||
BOOL hasBugWhichPreventsNonEditablePaste;
|
||||
BOOL hasBugWhichPreventsNonEditablePasteRedirect;
|
||||
BOOL supportsNativeCopyAndPaste;
|
||||
BOOL hasBugWhichPreventsNonEditablePaste;
|
||||
BOOL hasBugWhichPreventsNonEditablePasteRedirect;
|
||||
|
||||
BOOL currentEventIsNativePasteEvent;
|
||||
BOOL currentEventIsNativeCopyOrCutEvent;
|
||||
BOOL currentEventShouldBeSuppressed;
|
||||
BOOL currentEventShouldDefinitelyBubble;
|
||||
BOOL currentEventShouldDefinitelyNotBubble;
|
||||
BOOL currentEventIsNativePasteEvent;
|
||||
BOOL currentEventIsNativeCopyOrCutEvent;
|
||||
BOOL currentEventShouldBeSuppressed;
|
||||
BOOL currentEventShouldDefinitelyBubble;
|
||||
BOOL currentEventShouldDefinitelyNotBubble;
|
||||
|
||||
BOOL _ignoreNativeCopyOrCutEvent;
|
||||
BOOL _ignoreNativePastePreparation;
|
||||
BOOL _ignoreNativeCopyOrCutEvent;
|
||||
BOOL _ignoreNativePastePreparation;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
supportsNativeCopyAndPaste = CPFeatureIsCompatible(CPJavaScriptClipboardEventsFeature);
|
||||
hasBugWhichPreventsNonEditablePaste = CPPlatformHasBug(CPJavaScriptPasteRequiresEditableTarget);
|
||||
hasBugWhichPreventsNonEditablePasteRedirect = CPPlatformHasBug(CPJavaScriptPasteCantRefocus);
|
||||
}
|
||||
if (self = [super init])
|
||||
{
|
||||
supportsNativeCopyAndPaste = CPFeatureIsCompatible(CPJavaScriptClipboardEventsFeature);
|
||||
hasBugWhichPreventsNonEditablePaste = CPPlatformHasBug(CPJavaScriptPasteRequiresEditableTarget);
|
||||
hasBugWhichPreventsNonEditablePasteRedirect = CPPlatformHasBug(CPJavaScriptPasteCantRefocus);
|
||||
}
|
||||
|
||||
return self;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setDOMWindow:(DOMWindow)aDOMWindow
|
||||
{
|
||||
if (_DOMWindow === aDOMWindow)
|
||||
return;
|
||||
if (_DOMWindow === aDOMWindow)
|
||||
return;
|
||||
|
||||
if (_DOMWindow)
|
||||
[self destroyDOMElements];
|
||||
if (_DOMWindow)
|
||||
[self destroyDOMElements];
|
||||
|
||||
_DOMWindow = aDOMWindow;
|
||||
_DOMWindow = aDOMWindow;
|
||||
|
||||
if (_DOMWindow)
|
||||
[self createDOMElements];
|
||||
if (_DOMWindow)
|
||||
[self createDOMElements];
|
||||
}
|
||||
|
||||
- (void)createDOMElements
|
||||
{
|
||||
// MODIFICATION: Replaced 'var' with 'const'/'let'.
|
||||
const theDocument = _DOMWindow.document,
|
||||
_DOMBodyElement = theDocument.getElementById("cappuccino-body") || theDocument.body;
|
||||
var theDocument = _DOMWindow.document,
|
||||
_DOMBodyElement = theDocument.getElementById("cappuccino-body") || theDocument.body;
|
||||
|
||||
// Create Native Pasteboard handler.
|
||||
_DOMPasteboardElement = theDocument.createElement("textarea");
|
||||
// Create Native Pasteboard handler.
|
||||
_DOMPasteboardElement = theDocument.createElement("textarea");
|
||||
|
||||
_DOMPasteboardElement.style.position = "absolute";
|
||||
_DOMPasteboardElement.style.top = "-10000px";
|
||||
_DOMPasteboardElement.style.zIndex = "999";
|
||||
_DOMPasteboardElement.className = "cpdontremove";
|
||||
_DOMPasteboardElement.style.position = "absolute";
|
||||
_DOMPasteboardElement.style.top = "-10000px";
|
||||
_DOMPasteboardElement.style.zIndex = "999";
|
||||
_DOMPasteboardElement.className = "cpdontremove";
|
||||
|
||||
_DOMBodyElement.appendChild(_DOMPasteboardElement);
|
||||
_DOMBodyElement.appendChild(_DOMPasteboardElement);
|
||||
|
||||
_DOMPasteboardElement.blur();
|
||||
_DOMPasteboardElement.blur();
|
||||
|
||||
// MODIFICATION: Replaced 'var' with 'const'.
|
||||
const copyEventCallback = function (anEvent) { return [self beforeCopyEvent:anEvent]; },
|
||||
nativeBeforeClipboardEventCallback = function (anEvent) { return [self nativeBeforeClipboardEvent:anEvent]; },
|
||||
nativeCopyOrCutEventCallback = function (anEvent) { return [self nativeCopyOrCutEvent:anEvent]; },
|
||||
pasteEventCallback = function (anEvent) { return [self beforePasteEvent:anEvent]; },
|
||||
nativePasteEventCallback = function (anEvent) { return [self nativePasteEvent:anEvent]; };
|
||||
var copyEventCallback = function (anEvent) { return [self beforeCopyEvent:anEvent]; },
|
||||
nativeBeforeClipboardEventCallback = function (anEvent) { return [self nativeBeforeClipboardEvent:anEvent]; },
|
||||
nativeCopyOrCutEventCallback = function (anEvent) { return [self nativeCopyOrCutEvent:anEvent]; },
|
||||
pasteEventCallback = function (anEvent) { return [self beforePasteEvent:anEvent]; },
|
||||
nativePasteEventCallback = function (anEvent) { return [self nativePasteEvent:anEvent]; };
|
||||
|
||||
// MODIFICATION: Removed the 'if (theDocument.addEventListener)' check and the IE 'else' block.
|
||||
// Modern browsers natively support addEventListener.
|
||||
if (supportsNativeCopyAndPaste)
|
||||
{
|
||||
_DOMWindow.addEventListener("beforecopy", nativeBeforeClipboardEventCallback, NO);
|
||||
_DOMWindow.addEventListener("beforecut", nativeBeforeClipboardEventCallback, NO);
|
||||
_DOMWindow.addEventListener("beforepaste", nativeBeforeClipboardEventCallback, NO);
|
||||
_DOMWindow.addEventListener("copy", nativeCopyOrCutEventCallback, NO);
|
||||
_DOMWindow.addEventListener("cut", nativeCopyOrCutEventCallback, NO);
|
||||
_DOMWindow.addEventListener("paste", nativePasteEventCallback, NO);
|
||||
}
|
||||
else
|
||||
{
|
||||
theDocument.addEventListener("beforepaste", pasteEventCallback, NO);
|
||||
theDocument.addEventListener("beforecopy", copyEventCallback, NO);
|
||||
theDocument.addEventListener("beforecut", copyEventCallback, NO);
|
||||
}
|
||||
if (theDocument.addEventListener)
|
||||
{
|
||||
if (supportsNativeCopyAndPaste)
|
||||
{
|
||||
_DOMWindow.addEventListener("beforecopy", nativeBeforeClipboardEventCallback, NO);
|
||||
_DOMWindow.addEventListener("beforecut", nativeBeforeClipboardEventCallback, NO);
|
||||
_DOMWindow.addEventListener("beforepaste", nativeBeforeClipboardEventCallback, NO);
|
||||
_DOMWindow.addEventListener("copy", nativeCopyOrCutEventCallback, NO);
|
||||
_DOMWindow.addEventListener("cut", nativeCopyOrCutEventCallback, NO);
|
||||
_DOMWindow.addEventListener("paste", nativePasteEventCallback, NO);
|
||||
}
|
||||
else
|
||||
{
|
||||
theDocument.addEventListener("beforepaste", pasteEventCallback, NO);
|
||||
theDocument.addEventListener("beforecopy", copyEventCallback, NO);
|
||||
theDocument.addEventListener("beforecut", copyEventCallback, NO);
|
||||
}
|
||||
|
||||
_DOMWindow.addEventListener("unload", function()
|
||||
{
|
||||
if (supportsNativeCopyAndPaste)
|
||||
{
|
||||
_DOMWindow.removeEventListener("beforecopy", nativeBeforeClipboardEventCallback, NO);
|
||||
_DOMWindow.removeEventListener("beforecut", nativeBeforeClipboardEventCallback, NO);
|
||||
_DOMWindow.removeEventListener("beforepaste", nativeBeforeClipboardEventCallback, NO);
|
||||
_DOMWindow.removeEventListener("copy", nativeCopyOrCutEventCallback, NO);
|
||||
_DOMWindow.removeEventListener("cut", nativeCopyOrCutEventCallback, NO);
|
||||
_DOMWindow.removeEventListener("paste", nativePasteEventCallback, NO);
|
||||
}
|
||||
else
|
||||
{
|
||||
theDocument.removeEventListener("beforepaste", pasteEventCallback, NO);
|
||||
theDocument.removeEventListener("beforecopy", copyEventCallback, NO);
|
||||
theDocument.removeEventListener("beforecut", copyEventCallback, NO);
|
||||
}
|
||||
}, NO);
|
||||
_DOMWindow.addEventListener("unload", function()
|
||||
{
|
||||
if (supportsNativeCopyAndPaste)
|
||||
{
|
||||
_DOMWindow.removeEventListener("beforecopy", nativeBeforeClipboardEventCallback, NO);
|
||||
_DOMWindow.removeEventListener("beforecut", nativeBeforeClipboardEventCallback, NO);
|
||||
_DOMWindow.removeEventListener("beforepaste", nativeBeforeClipboardEventCallback, NO);
|
||||
_DOMWindow.removeEventListener("copy", nativeCopyOrCutEventCallback, NO);
|
||||
_DOMWindow.removeEventListener("cut", nativeCopyOrCutEventCallback, NO);
|
||||
_DOMWindow.removeEventListener("paste", nativePasteEventCallback, NO);
|
||||
}
|
||||
else
|
||||
{
|
||||
theDocument.removeEventListener("beforepaste", pasteEventCallback, NO);
|
||||
theDocument.removeEventListener("beforecopy", copyEventCallback, NO);
|
||||
theDocument.removeEventListener("beforecut", copyEventCallback, NO);
|
||||
}
|
||||
}, NO);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO If we wanted IE 8 and lower copy and paste it'd go here.
|
||||
}
|
||||
}
|
||||
|
||||
- (void)destroyDOMElements
|
||||
{
|
||||
// MODIFICATION: Replaced 'var' with 'const'.
|
||||
const theDocument = _DOMWindow.document,
|
||||
_DOMBodyElement = theDocument.getElementById("cappuccino-body") || theDocument.body;
|
||||
var theDocument = _DOMWindow.document,
|
||||
_DOMBodyElement = theDocument.getElementById("cappuccino-body") || theDocument.body;
|
||||
|
||||
_DOMBodyElement.removeChild(_DOMPasteboardElement);
|
||||
_DOMPasteboardElement = nil;
|
||||
_DOMBodyElement.removeChild(_DOMPasteboardElement);
|
||||
_DOMPasteboardElement = nil;
|
||||
}
|
||||
|
||||
- (void)windowMaySendKeyEvent:(CPEvent)anEvent
|
||||
{
|
||||
// Reset our opinions.
|
||||
currentEventIsNativePasteEvent = NO;
|
||||
currentEventIsNativeCopyOrCutEvent = NO;
|
||||
currentEventShouldBeSuppressed = NO;
|
||||
currentEventShouldDefinitelyNotBubble = NO;
|
||||
currentEventShouldDefinitelyBubble = NO;
|
||||
// Reset our opinions.
|
||||
currentEventIsNativePasteEvent = NO;
|
||||
currentEventIsNativeCopyOrCutEvent = NO;
|
||||
currentEventShouldBeSuppressed = NO;
|
||||
currentEventShouldDefinitelyNotBubble = NO;
|
||||
currentEventShouldDefinitelyBubble = NO;
|
||||
|
||||
if (!anEvent)
|
||||
return;
|
||||
if (!anEvent)
|
||||
return;
|
||||
|
||||
if ([anEvent type] !== CPKeyDown)
|
||||
{
|
||||
// Reset these flags on key up.
|
||||
_ignoreNativePastePreparation = NO;
|
||||
_ignoreNativeCopyOrCutEvent = NO;
|
||||
return;
|
||||
}
|
||||
if ([anEvent type] !== CPKeyDown)
|
||||
{
|
||||
// Reset these flags on key up.
|
||||
_ignoreNativePastePreparation = NO;
|
||||
_ignoreNativeCopyOrCutEvent = NO;
|
||||
return;
|
||||
}
|
||||
|
||||
// MODIFICATION: Replaced 'var' with 'const'.
|
||||
const modifierFlags = [anEvent modifierFlags];
|
||||
var modifierFlags = [anEvent modifierFlags];
|
||||
|
||||
if (!(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)))
|
||||
return;
|
||||
if (!(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)))
|
||||
return;
|
||||
|
||||
const aDOMEvent = anEvent._DOMEvent,
|
||||
characters = [anEvent characters],
|
||||
mayRequireDOMPasteboardElement = [self _mayRequireDOMPasteboardElementHack:aDOMEvent flags:modifierFlags];
|
||||
var aDOMEvent = anEvent._DOMEvent,
|
||||
characters = [anEvent characters],
|
||||
mayRequireDOMPasteboardElement = [self _mayRequireDOMPasteboardElementHack:aDOMEvent flags:modifierFlags];
|
||||
|
||||
if (characters === "v" && mayRequireDOMPasteboardElement)
|
||||
{
|
||||
if (supportsNativeCopyAndPaste && hasBugWhichPreventsNonEditablePaste && hasBugWhichPreventsNonEditablePasteRedirect && !hasEditableTarget(aDOMEvent))
|
||||
{
|
||||
// You can't paste from the system clipboard into a non-editable area in Safari, neither using native
|
||||
// copy and paste nor our _DOMPasteboardElement hack. We will paste from the Cappuccino pasteboard only
|
||||
// and allow Safari to "beep" to indicate something went wrong.
|
||||
if (characters === "v" && mayRequireDOMPasteboardElement)
|
||||
{
|
||||
if (supportsNativeCopyAndPaste && hasBugWhichPreventsNonEditablePaste && hasBugWhichPreventsNonEditablePasteRedirect && !hasEditableTarget(aDOMEvent))
|
||||
{
|
||||
// You can't paste from the system clipboard into a non-editable area in Safari, neither using native
|
||||
// copy and paste nor our _DOMPasteboardElement hack. We will paste from the Cappuccino pasteboard only
|
||||
// and allow Safari to "beep" to indicate something went wrong.
|
||||
|
||||
// The key down will not result in a paste event being sent by Safari, so it's not a paste event.
|
||||
currentEventIsNativePasteEvent = NO;
|
||||
// Yes to get the beep.
|
||||
currentEventShouldDefinitelyBubble = YES;
|
||||
}
|
||||
else if (!(supportsNativeCopyAndPaste || hasBugWhichPreventsNonEditablePaste) && !_ignoreNativePastePreparation)
|
||||
{
|
||||
// We don't support native copy and paste so we must focus the _DOMPasteboardElement to receive the
|
||||
// paste content. This needs to be done at keyDown time (or in the case of modern Safari, before the keyDown,
|
||||
// which unfortunately isn't possible. See above.)
|
||||
_DOMPasteboardElement.focus();
|
||||
_DOMPasteboardElement.select();
|
||||
_DOMPasteboardElement.value = "";
|
||||
_DOMWindow.setNativeTimeout(function () { [self _checkDOMPasteboardElement]; }, 0);
|
||||
// The key down will not result in a paste event being sent by Safari, so it's not a paste event.
|
||||
currentEventIsNativePasteEvent = NO;
|
||||
// Yes to get the beep.
|
||||
currentEventShouldDefinitelyBubble = YES;
|
||||
}
|
||||
else if (!(supportsNativeCopyAndPaste || hasBugWhichPreventsNonEditablePaste) && !_ignoreNativePastePreparation)
|
||||
{
|
||||
// We don't support native copy and paste so we must focus the _DOMPasteboardElement to receive the
|
||||
// paste content. This needs to be done at keyDown time (or in the case of modern Safari, before the keyDown,
|
||||
// which unfortunately isn't possible. See above.)
|
||||
_DOMPasteboardElement.focus();
|
||||
_DOMPasteboardElement.select();
|
||||
_DOMPasteboardElement.value = "";
|
||||
_DOMWindow.setNativeTimeout(function () { [self _checkDOMPasteboardElement]; }, 0);
|
||||
|
||||
currentEventIsNativePasteEvent = YES;
|
||||
}
|
||||
else if (supportsNativeCopyAndPaste)
|
||||
currentEventIsNativePasteEvent = YES;
|
||||
currentEventIsNativePasteEvent = YES;
|
||||
}
|
||||
else if (supportsNativeCopyAndPaste)
|
||||
currentEventIsNativePasteEvent = YES;
|
||||
|
||||
if (currentEventIsNativePasteEvent)
|
||||
{
|
||||
// We need the event to propagate or nothing will be pasted.
|
||||
currentEventShouldDefinitelyBubble = YES;
|
||||
if (currentEventIsNativePasteEvent)
|
||||
{
|
||||
// We need the event to propagate or nothing will be pasted.
|
||||
currentEventShouldDefinitelyBubble = YES;
|
||||
|
||||
// And we don't send the keydown because either our native paste envent handler will send it,
|
||||
// or the _checkDOMPasteboardElement check will.
|
||||
currentEventShouldBeSuppressed = YES;
|
||||
}
|
||||
}
|
||||
else if ((characters == "c" || characters == "x") && mayRequireDOMPasteboardElement)
|
||||
{
|
||||
currentEventIsNativeCopyOrCutEvent = YES;
|
||||
// And we don't send the keydown because either our native paste envent handler will send it,
|
||||
// or the _checkDOMPasteboardElement check will.
|
||||
currentEventShouldBeSuppressed = YES;
|
||||
}
|
||||
}
|
||||
else if ((characters == "c" || characters == "x") && mayRequireDOMPasteboardElement)
|
||||
{
|
||||
currentEventIsNativeCopyOrCutEvent = YES;
|
||||
|
||||
// If _ignoreNativeCopyOrCutEvent, we already handled the copy/cut in beforeCopyEvent:.
|
||||
// If supportsNativeCopyAndPaste, we will be handling it in the nativebeforeCopyEvent: handler.
|
||||
// In both of those cases we don't want to send the event on keydown too, or we'll get 2X copy/cut operations.
|
||||
if (supportsNativeCopyAndPaste || _ignoreNativeCopyOrCutEvent)
|
||||
currentEventShouldBeSuppressed = YES;
|
||||
}
|
||||
// If _ignoreNativeCopyOrCutEvent, we already handled the copy/cut in beforeCopyEvent:.
|
||||
// If supportsNativeCopyAndPaste, we will be handling it in the nativebeforeCopyEvent: handler.
|
||||
// In both of those cases we don't want to send the event on keydown too, or we'll get 2X copy/cut operations.
|
||||
if (supportsNativeCopyAndPaste || _ignoreNativeCopyOrCutEvent)
|
||||
currentEventShouldBeSuppressed = YES;
|
||||
}
|
||||
|
||||
if (CPFeatureIsCompatible(CPBackspaceTriggersPageBack) && characters === CPDeleteCharacter && !hasEditableTarget(aDOMEvent))
|
||||
currentEventShouldBeSuppressed = YES;
|
||||
if (CPFeatureIsCompatible(CPBackspaceTriggersPageBack) && characters === CPDeleteCharacter && !hasEditableTarget(aDOMEvent))
|
||||
currentEventShouldBeSuppressed = YES;
|
||||
|
||||
if (!currentEventShouldBeSuppressed)
|
||||
{
|
||||
// MODIFICATION: Inlined the SUPPRESS_CAPPUCCINO_PASTE_FOR_EVENT macro.
|
||||
if (characters === "v")
|
||||
anEvent._suppressCappuccinoPaste = YES;
|
||||
// MODIFICATION: Inlined the SUPPRESS_CAPPUCCINO_CUT_FOR_EVENT macro.
|
||||
else if (characters === "x")
|
||||
anEvent._suppressCappuccinoCut = YES;
|
||||
}
|
||||
if (!currentEventShouldBeSuppressed)
|
||||
{
|
||||
if (characters === "v")
|
||||
SUPPRESS_CAPPUCCINO_PASTE_FOR_EVENT(anEvent);
|
||||
else if (characters === "x")
|
||||
SUPPRESS_CAPPUCCINO_CUT_FOR_EVENT(anEvent);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)windowShouldSuppressKeyEvent
|
||||
{
|
||||
return currentEventShouldBeSuppressed;
|
||||
return currentEventShouldBeSuppressed;
|
||||
}
|
||||
|
||||
- (void)windowDidSendKeyEvent:(CPEvent)anEvent
|
||||
{
|
||||
// Now that the copy event has been sent through the Cappuccino event stack, we can load any Cappuccino
|
||||
// pasteboard string into our DOMPasteboardElement hack, if necessary.
|
||||
if (!supportsNativeCopyAndPaste && currentEventIsNativeCopyOrCutEvent)
|
||||
[self _primeDOMPasteboardElement];
|
||||
// Now that the copy event has been sent through the Cappuccino event stack, we can load any Cappuccino
|
||||
// pasteboard string into our DOMPasteboardElement hack, if necessary.
|
||||
if (!supportsNativeCopyAndPaste && currentEventIsNativeCopyOrCutEvent)
|
||||
[self _primeDOMPasteboardElement];
|
||||
}
|
||||
|
||||
- (BOOL)windowShouldStopPropagation
|
||||
{
|
||||
return currentEventShouldDefinitelyNotBubble;
|
||||
return currentEventShouldDefinitelyNotBubble;
|
||||
}
|
||||
|
||||
- (BOOL)windowShouldNotStopPropagation
|
||||
{
|
||||
return currentEventShouldDefinitelyBubble;
|
||||
return currentEventShouldDefinitelyBubble;
|
||||
}
|
||||
|
||||
- (CPEvent)_fakeClipboardEvent:(DOMEvent)aDOMEvent type:(CPString)aType
|
||||
{
|
||||
// MODIFICATION: Replaced 'var' with 'const'.
|
||||
const keyCode = aType === "x" ? CPKeyCodes.X : (aType === "c" ? CPKeyCodes.C : CPKeyCodes.V),
|
||||
characters = aType,
|
||||
timestamp = [CPEvent currentTimestamp], // fake event, might as well use current timestamp
|
||||
windowNumber = [[CPApp keyWindow] windowNumber],
|
||||
modifierFlags = CPPlatformActionKeyMask,
|
||||
location = [[CPApp currentEvent] locationInWindow],
|
||||
anEvent = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags
|
||||
timestamp:timestamp windowNumber:windowNumber context:nil
|
||||
characters:characters charactersIgnoringModifiers:characters isARepeat:NO keyCode:keyCode isActionKey:YES];
|
||||
var keyCode = aType === "x" ? CPKeyCodes.X : (aType === "c" ? CPKeyCodes.C : CPKeyCodes.V),
|
||||
characters = aType,
|
||||
timestamp = [CPEvent currentTimestamp], // fake event, might as well use current timestamp
|
||||
windowNumber = [[CPApp keyWindow] windowNumber],
|
||||
modifierFlags = CPPlatformActionKeyMask,
|
||||
location = [[CPApp currentEvent] locationInWindow],
|
||||
anEvent = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags
|
||||
timestamp:timestamp windowNumber:windowNumber context:nil
|
||||
characters:characters charactersIgnoringModifiers:characters isARepeat:NO keyCode:keyCode isActionKey:YES];
|
||||
|
||||
anEvent._data1 = @{ "simulated": YES };
|
||||
anEvent._DOMEvent = aDOMEvent;
|
||||
anEvent._data1 = @{ "simulated": YES };
|
||||
anEvent._DOMEvent = aDOMEvent;
|
||||
|
||||
return anEvent;
|
||||
return anEvent;
|
||||
}
|
||||
|
||||
- (void)beforeCopyEvent:(DOMEvent)aDOMEvent
|
||||
{
|
||||
if ([self _mayRequireDOMPasteboardElementHack:aDOMEvent flags:CPPlatformActionKeyMask] && !_ignoreNativeCopyOrCutEvent)
|
||||
{
|
||||
// we have to send out a fake copy or cut event so that we can force the copy/cut mechanisms to take place
|
||||
// MODIFICATION: Replaced 'var' with 'const'.
|
||||
const anEvent = [self _fakeClipboardEvent:aDOMEvent type:(aDOMEvent.type === "beforecut" ? "x" : "c")];
|
||||
if ([self _mayRequireDOMPasteboardElementHack:aDOMEvent flags:CPPlatformActionKeyMask] && !_ignoreNativeCopyOrCutEvent)
|
||||
{
|
||||
// we have to send out a fake copy or cut event so that we can force the copy/cut mechanisms to take place
|
||||
var anEvent = [self _fakeClipboardEvent:aDOMEvent type:(aDOMEvent.type === "beforecut" ? "x" : "c")];
|
||||
|
||||
[CPApp sendEvent:anEvent];
|
||||
[CPApp sendEvent:anEvent];
|
||||
|
||||
// Once we've sent it, we can load the copy information into the pasteboard hack.
|
||||
[self _primeDOMPasteboardElement];
|
||||
// Once we've sent it, we can load the copy information into the pasteboard hack.
|
||||
[self _primeDOMPasteboardElement];
|
||||
|
||||
//then we have to IGNORE the real keyboard event to prevent a double copy
|
||||
//safari also sends the beforecopy event twice, so we additionally check here and prevent two events
|
||||
_ignoreNativeCopyOrCutEvent = YES;
|
||||
}
|
||||
//then we have to IGNORE the real keyboard event to prevent a double copy
|
||||
//safari also sends the beforecopy event twice, so we additionally check here and prevent two events
|
||||
_ignoreNativeCopyOrCutEvent = YES;
|
||||
}
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
- (BOOL)beforePasteEvent:(DOMEvent)aDOMEvent
|
||||
{
|
||||
// Set up to capture the paste in a temporary input field. We'll send the event after capture.
|
||||
if ([self _mayRequireDOMPasteboardElementHack:aDOMEvent flags:CPPlatformActionKeyMask])
|
||||
{
|
||||
_DOMPasteboardElement.focus();
|
||||
_DOMPasteboardElement.select();
|
||||
_DOMPasteboardElement.value = "";
|
||||
// Set up to capture the paste in a temporary input field. We'll send the event after capture.
|
||||
if ([self _mayRequireDOMPasteboardElementHack:aDOMEvent flags:CPPlatformActionKeyMask])
|
||||
{
|
||||
_DOMPasteboardElement.focus();
|
||||
_DOMPasteboardElement.select();
|
||||
_DOMPasteboardElement.value = "";
|
||||
|
||||
_ignoreNativePastePreparation = YES;
|
||||
}
|
||||
_ignoreNativePastePreparation = YES;
|
||||
}
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
/*
|
||||
Return true if the event may be a copy and paste event, but the target is not an input or text area.
|
||||
*/
|
||||
Return true if the event may be a copy and paste event, but the target is not an input or text area.
|
||||
*/
|
||||
- (BOOL)_mayRequireDOMPasteboardElementHack:(DOMEvent)aDOMEvent flags:(unsigned)modifierFlags
|
||||
{
|
||||
return !hasEditableTarget(aDOMEvent) && (modifierFlags & CPPlatformActionKeyMask);
|
||||
return !hasEditableTarget(aDOMEvent) && (modifierFlags & CPPlatformActionKeyMask);
|
||||
}
|
||||
|
||||
- (void)_primeDOMPasteboardElement
|
||||
{
|
||||
// MODIFICATION: Replaced 'var' with 'const'.
|
||||
const pasteboard = [CPPasteboard generalPasteboard],
|
||||
types = [pasteboard types];
|
||||
var pasteboard = [CPPasteboard generalPasteboard],
|
||||
types = [pasteboard types];
|
||||
|
||||
if (types.length)
|
||||
{
|
||||
if ([types indexOfObjectIdenticalTo:CPStringPboardType] !== CPNotFound)
|
||||
_DOMPasteboardElement.value = [pasteboard stringForType:CPStringPboardType];
|
||||
else
|
||||
_DOMPasteboardElement.value = [pasteboard _generateStateUID];
|
||||
if (types.length)
|
||||
{
|
||||
if ([types indexOfObjectIdenticalTo:CPStringPboardType] !== CPNotFound)
|
||||
_DOMPasteboardElement.value = [pasteboard stringForType:CPStringPboardType];
|
||||
else
|
||||
_DOMPasteboardElement.value = [pasteboard _generateStateUID];
|
||||
|
||||
_DOMPasteboardElement.focus();
|
||||
_DOMPasteboardElement.select();
|
||||
_DOMPasteboardElement.focus();
|
||||
_DOMPasteboardElement.select();
|
||||
|
||||
window.setNativeTimeout(function() { [self _clearDOMPasteboardElement]; }, 0);
|
||||
}
|
||||
window.setNativeTimeout(function() { [self _clearDOMPasteboardElement]; }, 0);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_checkDOMPasteboardElement
|
||||
{
|
||||
if (supportsNativeCopyAndPaste)
|
||||
{
|
||||
[self _clearDOMPasteboardElement];
|
||||
return;
|
||||
}
|
||||
if (supportsNativeCopyAndPaste)
|
||||
{
|
||||
[self _clearDOMPasteboardElement];
|
||||
return;
|
||||
}
|
||||
|
||||
// MODIFICATION: Replaced 'var' with 'const'.
|
||||
const value = _DOMPasteboardElement.value;
|
||||
var value = _DOMPasteboardElement.value;
|
||||
|
||||
if ([value length])
|
||||
{
|
||||
// MODIFICATION: Replaced 'var' with 'const'.
|
||||
const pasteboard = [CPPasteboard generalPasteboard],
|
||||
cappString = [pasteboard stringForType:CPStringPboardType];
|
||||
if ([value length])
|
||||
{
|
||||
var pasteboard = [CPPasteboard generalPasteboard],
|
||||
cappString = [pasteboard stringForType:CPStringPboardType];
|
||||
|
||||
if (cappString != value)
|
||||
{
|
||||
[pasteboard declareTypes:[CPStringPboardType] owner:self];
|
||||
[pasteboard setString:value forType:CPStringPboardType];
|
||||
}
|
||||
}
|
||||
if (cappString != value)
|
||||
{
|
||||
[pasteboard declareTypes:[CPStringPboardType] owner:self];
|
||||
[pasteboard setString:value forType:CPStringPboardType];
|
||||
}
|
||||
}
|
||||
|
||||
[self _clearDOMPasteboardElement];
|
||||
[self _clearDOMPasteboardElement];
|
||||
|
||||
[CPApp sendEvent:[self _fakeClipboardEvent:nil type:@"v"]];
|
||||
[CPApp sendEvent:[self _fakeClipboardEvent:nil type:@"v"]];
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
- (void)_clearDOMPasteboardElement
|
||||
{
|
||||
_DOMPasteboardElement.value = "";
|
||||
_DOMPasteboardElement.blur();
|
||||
_DOMPasteboardElement.value = "";
|
||||
_DOMPasteboardElement.blur();
|
||||
}
|
||||
|
||||
- (BOOL)nativeBeforeClipboardEvent:(DOMEvent)aDOMEvent
|
||||
{
|
||||
// Our job here is to return "false" if the given clipboard operation should be enabled even in a situation where
|
||||
// the browser might normally grey the option out.
|
||||
// Our job here is to return "false" if the given clipboard operation should be enabled even in a situation where
|
||||
// the browser might normally grey the option out.
|
||||
|
||||
// Allow these fields to do their own thing.
|
||||
if (hasEditableTarget(aDOMEvent))
|
||||
return true;
|
||||
// Allow these fields to do their own thing.
|
||||
if (hasEditableTarget(aDOMEvent))
|
||||
return true;
|
||||
|
||||
// MODIFICATION: Replaced 'var' with 'let'.
|
||||
let returnValue = YES;
|
||||
var returnValue = YES;
|
||||
|
||||
switch (aDOMEvent.type)
|
||||
{
|
||||
case "beforecopy":
|
||||
returnValue = !([CPApp targetForAction:@selector(copy:)]);
|
||||
break;
|
||||
case "beforecut":
|
||||
returnValue = !([CPApp targetForAction:@selector(cut:)]);
|
||||
break;
|
||||
case "beforepaste":
|
||||
returnValue = !([CPApp targetForAction:@selector(paste:)]);
|
||||
break;
|
||||
}
|
||||
switch (aDOMEvent.type)
|
||||
{
|
||||
case "beforecopy":
|
||||
returnValue = !([CPApp targetForAction:@selector(copy:)]);
|
||||
break;
|
||||
case "beforecut":
|
||||
returnValue = !([CPApp targetForAction:@selector(cut:)]);
|
||||
break;
|
||||
case "beforepaste":
|
||||
returnValue = !([CPApp targetForAction:@selector(paste:)]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!returnValue)
|
||||
_CPDOMEventStop(aDOMEvent, self);
|
||||
if (!returnValue)
|
||||
_CPDOMEventStop(aDOMEvent, self);
|
||||
|
||||
return returnValue;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
- (BOOL)nativePasteEvent:(DOMEvent)aDOMEvent
|
||||
{
|
||||
// This shouldn't happen.
|
||||
if (!supportsNativeCopyAndPaste)
|
||||
return;
|
||||
// This shouldn't happen.
|
||||
if (!supportsNativeCopyAndPaste)
|
||||
return;
|
||||
|
||||
// MODIFICATION: Replaced 'var' with 'let'.
|
||||
let value;
|
||||
if (aDOMEvent.clipboardData && aDOMEvent.clipboardData.setData)
|
||||
value = aDOMEvent.clipboardData.getData('text/plain');
|
||||
else
|
||||
value = _DOMWindow.clipboardData.getData("Text");
|
||||
var value;
|
||||
if (aDOMEvent.clipboardData && aDOMEvent.clipboardData.setData)
|
||||
value = aDOMEvent.clipboardData.getData('text/plain');
|
||||
else
|
||||
value = _DOMWindow.clipboardData.getData("Text");
|
||||
|
||||
if ([value length])
|
||||
{
|
||||
// MODIFICATION: Replaced 'var' with 'const'.
|
||||
const pasteboard = [CPPasteboard generalPasteboard],
|
||||
cappString = [pasteboard stringForType:CPStringPboardType];
|
||||
if ([value length])
|
||||
{
|
||||
var pasteboard = [CPPasteboard generalPasteboard],
|
||||
cappString = [pasteboard stringForType:CPStringPboardType];
|
||||
|
||||
if (cappString != value)
|
||||
{
|
||||
[pasteboard declareTypes:[CPStringPboardType] owner:self];
|
||||
[pasteboard setString:value forType:CPStringPboardType];
|
||||
}
|
||||
}
|
||||
if (cappString != value)
|
||||
{
|
||||
[pasteboard declareTypes:[CPStringPboardType] owner:self];
|
||||
[pasteboard setString:value forType:CPStringPboardType];
|
||||
}
|
||||
}
|
||||
|
||||
// MODIFICATION: Replaced 'var' with 'const'.
|
||||
const anEvent = [self _fakeClipboardEvent:aDOMEvent type:"v"],
|
||||
platformWindow = [[anEvent window] platformWindow];
|
||||
var anEvent = [self _fakeClipboardEvent:aDOMEvent type:"v"],
|
||||
platformWindow = [[anEvent window] platformWindow];
|
||||
|
||||
// MODIFICATION: Inlined the SUPPRESS_CAPPUCCINO_PASTE_FOR_EVENT macro.
|
||||
anEvent._suppressCappuccinoPaste = YES;
|
||||
SUPPRESS_CAPPUCCINO_PASTE_FOR_EVENT(anEvent);
|
||||
|
||||
// By default we'll stop the native handling of the event since we're handling it ourselves. However, we need to
|
||||
// stop it before we send the event so that the event can overrule our choice. CPTextField for instance wants the
|
||||
// default handling when focused (which is to insert into the field).
|
||||
[platformWindow _propagateCurrentDOMEvent:NO];
|
||||
// By default we'll stop the native handling of the event since we're handling it ourselves. However, we need to
|
||||
// stop it before we send the event so that the event can overrule our choice. CPTextField for instance wants the
|
||||
// default handling when focused (which is to insert into the field).
|
||||
[platformWindow _propagateCurrentDOMEvent:NO];
|
||||
|
||||
[CPApp sendEvent:anEvent];
|
||||
[CPApp sendEvent:anEvent];
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
|
||||
if (![platformWindow _willPropagateCurrentDOMEvent])
|
||||
_CPDOMEventStop(aDOMEvent, self);
|
||||
if (![platformWindow _willPropagateCurrentDOMEvent])
|
||||
_CPDOMEventStop(aDOMEvent, self);
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
- (BOOL)nativeCopyOrCutEvent:(DOMEvent)aDOMEvent
|
||||
{
|
||||
// This shouldn't happen.
|
||||
if (!supportsNativeCopyAndPaste)
|
||||
return;
|
||||
// This shouldn't happen.
|
||||
if (!supportsNativeCopyAndPaste)
|
||||
return;
|
||||
|
||||
// MODIFICATION: Replaced 'var' with 'const'.
|
||||
const anEvent = [self _fakeClipboardEvent:aDOMEvent type:(aDOMEvent.type.indexOf("cut") != CPNotFound ? "x" : "c")],
|
||||
platformWindow = [[anEvent window] platformWindow];
|
||||
var anEvent = [self _fakeClipboardEvent:aDOMEvent type:(aDOMEvent.type.indexOf("cut") != CPNotFound ? "x" : "c")],
|
||||
platformWindow = [[anEvent window] platformWindow];
|
||||
|
||||
// MODIFICATION: Inlined the SUPPRESS_CAPPUCCINO_CUT_FOR_EVENT macro.
|
||||
anEvent._suppressCappuccinoCut = YES;
|
||||
SUPPRESS_CAPPUCCINO_CUT_FOR_EVENT(anEvent);
|
||||
|
||||
[platformWindow _propagateCurrentDOMEvent:NO];
|
||||
[platformWindow _propagateCurrentDOMEvent:NO];
|
||||
|
||||
// Let the app react through copy: and cut: actions.
|
||||
[CPApp sendEvent:anEvent];
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
// Let the app react through copy: and cut: actions.
|
||||
[CPApp sendEvent:anEvent];
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
|
||||
// If StopDOMEventPropagation was set to NO, we don't try to write to the system clipboard. The control that did this
|
||||
// wants to use the default copy/cut functionality.
|
||||
if (![platformWindow _willPropagateCurrentDOMEvent])
|
||||
{
|
||||
// Now the app should have written whatever it wants to have copied to the Cappuccino clipboard. So now we need
|
||||
// to write it to the system board.
|
||||
_CPDOMEventStop(aDOMEvent, self);
|
||||
// If StopDOMEventPropagation was set to NO, we don't try to write to the system clipboard. The control that did this
|
||||
// wants to use the default copy/cut functionality.
|
||||
if (![platformWindow _willPropagateCurrentDOMEvent])
|
||||
{
|
||||
// Now the app should have written whatever it wants to have copied to the Cappuccino clipboard. So now we need
|
||||
// to write it to the system board.
|
||||
_CPDOMEventStop(aDOMEvent, self);
|
||||
|
||||
// MODIFICATION: Replaced 'var' with 'const'.
|
||||
const pasteboard = [CPPasteboard generalPasteboard];
|
||||
var pasteboard = [CPPasteboard generalPasteboard];
|
||||
|
||||
if ([[pasteboard types] containsObject:CPStringPboardType])
|
||||
{
|
||||
// MODIFICATION: Replaced 'var' with 'const'.
|
||||
const stringValue = [pasteboard stringForType:CPStringPboardType];
|
||||
if ([[pasteboard types] containsObject:CPStringPboardType])
|
||||
{
|
||||
var stringValue = [pasteboard stringForType:CPStringPboardType];
|
||||
|
||||
if (aDOMEvent.clipboardData && aDOMEvent.clipboardData.setData)
|
||||
aDOMEvent.clipboardData.setData('text/plain', stringValue);
|
||||
else
|
||||
_DOMWindow.clipboardData.setData('Text', stringValue);
|
||||
}
|
||||
}
|
||||
if (aDOMEvent.clipboardData && aDOMEvent.clipboardData.setData)
|
||||
aDOMEvent.clipboardData.setData('text/plain', stringValue);
|
||||
else
|
||||
_DOMWindow.clipboardData.setData('Text', stringValue);
|
||||
}
|
||||
}
|
||||
|
||||
return ![platformWindow _willPropagateCurrentDOMEvent];
|
||||
return ![platformWindow _willPropagateCurrentDOMEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in new issue
Block a user