mirror of
https://gitee.com/onvia/ccc-tnt-psd2ui
synced 2025-11-07 06:46:25 +00:00
支持 mac
This commit is contained in:
18
npm-packages/mac-v2.4.x/canvas/src/Backends.cc
Normal file
18
npm-packages/mac-v2.4.x/canvas/src/Backends.cc
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "Backends.h"
|
||||
|
||||
#include "backend/ImageBackend.h"
|
||||
#include "backend/PdfBackend.h"
|
||||
#include "backend/SvgBackend.h"
|
||||
|
||||
using namespace v8;
|
||||
|
||||
void Backends::Initialize(Local<Object> target) {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
Local<Object> obj = Nan::New<Object>();
|
||||
ImageBackend::Initialize(obj);
|
||||
PdfBackend::Initialize(obj);
|
||||
SvgBackend::Initialize(obj);
|
||||
|
||||
Nan::Set(target, Nan::New<String>("Backends").ToLocalChecked(), obj).Check();
|
||||
}
|
||||
10
npm-packages/mac-v2.4.x/canvas/src/Backends.h
Normal file
10
npm-packages/mac-v2.4.x/canvas/src/Backends.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "backend/Backend.h"
|
||||
#include <nan.h>
|
||||
#include <v8.h>
|
||||
|
||||
class Backends : public Nan::ObjectWrap {
|
||||
public:
|
||||
static void Initialize(v8::Local<v8::Object> target);
|
||||
};
|
||||
965
npm-packages/mac-v2.4.x/canvas/src/Canvas.cc
Normal file
965
npm-packages/mac-v2.4.x/canvas/src/Canvas.cc
Normal file
@@ -0,0 +1,965 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#include "Canvas.h"
|
||||
|
||||
#include <algorithm> // std::min
|
||||
#include <assert.h>
|
||||
#include <cairo-pdf.h>
|
||||
#include <cairo-svg.h>
|
||||
#include "CanvasRenderingContext2d.h"
|
||||
#include "closure.h"
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
#include <ctime>
|
||||
#include <glib.h>
|
||||
#include "PNG.h"
|
||||
#include "register_font.h"
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include "Util.h"
|
||||
#include <vector>
|
||||
#include "node_buffer.h"
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
#include "JPEGStream.h"
|
||||
#endif
|
||||
|
||||
#include "backend/ImageBackend.h"
|
||||
#include "backend/PdfBackend.h"
|
||||
#include "backend/SvgBackend.h"
|
||||
|
||||
#define GENERIC_FACE_ERROR \
|
||||
"The second argument to registerFont is required, and should be an object " \
|
||||
"with at least a family (string) and optionally weight (string/number) " \
|
||||
"and style (string)."
|
||||
|
||||
#define CHECK_RECEIVER(prop) \
|
||||
if (!Canvas::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { \
|
||||
Nan::ThrowTypeError("Method " #prop " called on incompatible receiver"); \
|
||||
return; \
|
||||
}
|
||||
|
||||
using namespace v8;
|
||||
using namespace std;
|
||||
|
||||
Nan::Persistent<FunctionTemplate> Canvas::constructor;
|
||||
|
||||
std::vector<FontFace> font_face_list;
|
||||
|
||||
/*
|
||||
* Initialize Canvas.
|
||||
*/
|
||||
|
||||
void
|
||||
Canvas::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
// Constructor
|
||||
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Canvas::New);
|
||||
constructor.Reset(ctor);
|
||||
ctor->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
ctor->SetClassName(Nan::New("Canvas").ToLocalChecked());
|
||||
|
||||
// Prototype
|
||||
Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
|
||||
Nan::SetPrototypeMethod(ctor, "toBuffer", ToBuffer);
|
||||
Nan::SetPrototypeMethod(ctor, "streamPNGSync", StreamPNGSync);
|
||||
Nan::SetPrototypeMethod(ctor, "streamPDFSync", StreamPDFSync);
|
||||
#ifdef HAVE_JPEG
|
||||
Nan::SetPrototypeMethod(ctor, "streamJPEGSync", StreamJPEGSync);
|
||||
#endif
|
||||
Nan::SetAccessor(proto, Nan::New("type").ToLocalChecked(), GetType);
|
||||
Nan::SetAccessor(proto, Nan::New("stride").ToLocalChecked(), GetStride);
|
||||
Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth, SetWidth);
|
||||
Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight, SetHeight);
|
||||
|
||||
Nan::SetTemplate(proto, "PNG_NO_FILTERS", Nan::New<Uint32>(PNG_NO_FILTERS));
|
||||
Nan::SetTemplate(proto, "PNG_FILTER_NONE", Nan::New<Uint32>(PNG_FILTER_NONE));
|
||||
Nan::SetTemplate(proto, "PNG_FILTER_SUB", Nan::New<Uint32>(PNG_FILTER_SUB));
|
||||
Nan::SetTemplate(proto, "PNG_FILTER_UP", Nan::New<Uint32>(PNG_FILTER_UP));
|
||||
Nan::SetTemplate(proto, "PNG_FILTER_AVG", Nan::New<Uint32>(PNG_FILTER_AVG));
|
||||
Nan::SetTemplate(proto, "PNG_FILTER_PAETH", Nan::New<Uint32>(PNG_FILTER_PAETH));
|
||||
Nan::SetTemplate(proto, "PNG_ALL_FILTERS", Nan::New<Uint32>(PNG_ALL_FILTERS));
|
||||
|
||||
// Class methods
|
||||
Nan::SetMethod(ctor, "_registerFont", RegisterFont);
|
||||
Nan::SetMethod(ctor, "_deregisterAllFonts", DeregisterAllFonts);
|
||||
|
||||
Local<Context> ctx = Nan::GetCurrentContext();
|
||||
Nan::Set(target,
|
||||
Nan::New("Canvas").ToLocalChecked(),
|
||||
ctor->GetFunction(ctx).ToLocalChecked());
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a Canvas with the given width and height.
|
||||
*/
|
||||
|
||||
NAN_METHOD(Canvas::New) {
|
||||
if (!info.IsConstructCall()) {
|
||||
return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
|
||||
}
|
||||
|
||||
Backend* backend = NULL;
|
||||
if (info[0]->IsNumber()) {
|
||||
int width = Nan::To<uint32_t>(info[0]).FromMaybe(0), height = 0;
|
||||
|
||||
if (info[1]->IsNumber()) height = Nan::To<uint32_t>(info[1]).FromMaybe(0);
|
||||
|
||||
if (info[2]->IsString()) {
|
||||
if (0 == strcmp("pdf", *Nan::Utf8String(info[2])))
|
||||
backend = new PdfBackend(width, height);
|
||||
else if (0 == strcmp("svg", *Nan::Utf8String(info[2])))
|
||||
backend = new SvgBackend(width, height);
|
||||
else
|
||||
backend = new ImageBackend(width, height);
|
||||
}
|
||||
else
|
||||
backend = new ImageBackend(width, height);
|
||||
}
|
||||
else if (info[0]->IsObject()) {
|
||||
if (Nan::New(ImageBackend::constructor)->HasInstance(info[0]) ||
|
||||
Nan::New(PdfBackend::constructor)->HasInstance(info[0]) ||
|
||||
Nan::New(SvgBackend::constructor)->HasInstance(info[0])) {
|
||||
backend = Nan::ObjectWrap::Unwrap<Backend>(Nan::To<Object>(info[0]).ToLocalChecked());
|
||||
}else{
|
||||
return Nan::ThrowTypeError("Invalid arguments");
|
||||
}
|
||||
}
|
||||
else {
|
||||
backend = new ImageBackend(0, 0);
|
||||
}
|
||||
|
||||
if (!backend->isSurfaceValid()) {
|
||||
delete backend;
|
||||
return Nan::ThrowError(backend->getError());
|
||||
}
|
||||
|
||||
Canvas* canvas = new Canvas(backend);
|
||||
canvas->Wrap(info.This());
|
||||
|
||||
backend->setCanvas(canvas);
|
||||
|
||||
info.GetReturnValue().Set(info.This());
|
||||
}
|
||||
|
||||
/*
|
||||
* Get type string.
|
||||
*/
|
||||
|
||||
NAN_GETTER(Canvas::GetType) {
|
||||
CHECK_RECEIVER(Canvas.GetType);
|
||||
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
|
||||
info.GetReturnValue().Set(Nan::New<String>(canvas->backend()->getName()).ToLocalChecked());
|
||||
}
|
||||
|
||||
/*
|
||||
* Get stride.
|
||||
*/
|
||||
NAN_GETTER(Canvas::GetStride) {
|
||||
CHECK_RECEIVER(Canvas.GetStride);
|
||||
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
|
||||
info.GetReturnValue().Set(Nan::New<Number>(canvas->stride()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get width.
|
||||
*/
|
||||
|
||||
NAN_GETTER(Canvas::GetWidth) {
|
||||
CHECK_RECEIVER(Canvas.GetWidth);
|
||||
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
|
||||
info.GetReturnValue().Set(Nan::New<Number>(canvas->getWidth()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Set width.
|
||||
*/
|
||||
|
||||
NAN_SETTER(Canvas::SetWidth) {
|
||||
CHECK_RECEIVER(Canvas.SetWidth);
|
||||
if (value->IsNumber()) {
|
||||
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
|
||||
canvas->backend()->setWidth(Nan::To<uint32_t>(value).FromMaybe(0));
|
||||
canvas->resurface(info.This());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get height.
|
||||
*/
|
||||
|
||||
NAN_GETTER(Canvas::GetHeight) {
|
||||
CHECK_RECEIVER(Canvas.GetHeight);
|
||||
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
|
||||
info.GetReturnValue().Set(Nan::New<Number>(canvas->getHeight()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Set height.
|
||||
*/
|
||||
|
||||
NAN_SETTER(Canvas::SetHeight) {
|
||||
CHECK_RECEIVER(Canvas.SetHeight);
|
||||
if (value->IsNumber()) {
|
||||
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
|
||||
canvas->backend()->setHeight(Nan::To<uint32_t>(value).FromMaybe(0));
|
||||
canvas->resurface(info.This());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* EIO toBuffer callback.
|
||||
*/
|
||||
|
||||
void
|
||||
Canvas::ToPngBufferAsync(uv_work_t *req) {
|
||||
PngClosure* closure = static_cast<PngClosure*>(req->data);
|
||||
|
||||
closure->status = canvas_write_to_png_stream(
|
||||
closure->canvas->surface(),
|
||||
PngClosure::writeVec,
|
||||
closure);
|
||||
}
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
void
|
||||
Canvas::ToJpegBufferAsync(uv_work_t *req) {
|
||||
JpegClosure* closure = static_cast<JpegClosure*>(req->data);
|
||||
write_to_jpeg_buffer(closure->canvas->surface(), closure);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* EIO after toBuffer callback.
|
||||
*/
|
||||
|
||||
void
|
||||
Canvas::ToBufferAsyncAfter(uv_work_t *req) {
|
||||
Nan::HandleScope scope;
|
||||
Nan::AsyncResource async("canvas:ToBufferAsyncAfter");
|
||||
Closure* closure = static_cast<Closure*>(req->data);
|
||||
delete req;
|
||||
|
||||
if (closure->status) {
|
||||
Local<Value> argv[1] = { Canvas::Error(closure->status) };
|
||||
closure->cb.Call(1, argv, &async);
|
||||
} else {
|
||||
Local<Object> buf = Nan::CopyBuffer((char*)&closure->vec[0], closure->vec.size()).ToLocalChecked();
|
||||
Local<Value> argv[2] = { Nan::Null(), buf };
|
||||
closure->cb.Call(sizeof argv / sizeof *argv, argv, &async);
|
||||
}
|
||||
|
||||
closure->canvas->Unref();
|
||||
delete closure;
|
||||
}
|
||||
|
||||
static void parsePNGArgs(Local<Value> arg, PngClosure& pngargs) {
|
||||
if (arg->IsObject()) {
|
||||
Local<Object> obj = Nan::To<Object>(arg).ToLocalChecked();
|
||||
|
||||
Local<Value> cLevel = Nan::Get(obj, Nan::New("compressionLevel").ToLocalChecked()).ToLocalChecked();
|
||||
if (cLevel->IsUint32()) {
|
||||
uint32_t val = Nan::To<uint32_t>(cLevel).FromMaybe(0);
|
||||
// See quote below from spec section 4.12.5.5.
|
||||
if (val <= 9) pngargs.compressionLevel = val;
|
||||
}
|
||||
|
||||
Local<Value> rez = Nan::Get(obj, Nan::New("resolution").ToLocalChecked()).ToLocalChecked();
|
||||
if (rez->IsUint32()) {
|
||||
uint32_t val = Nan::To<uint32_t>(rez).FromMaybe(0);
|
||||
if (val > 0) pngargs.resolution = val;
|
||||
}
|
||||
|
||||
Local<Value> filters = Nan::Get(obj, Nan::New("filters").ToLocalChecked()).ToLocalChecked();
|
||||
if (filters->IsUint32()) pngargs.filters = Nan::To<uint32_t>(filters).FromMaybe(0);
|
||||
|
||||
Local<Value> palette = Nan::Get(obj, Nan::New("palette").ToLocalChecked()).ToLocalChecked();
|
||||
if (palette->IsUint8ClampedArray()) {
|
||||
Local<Uint8ClampedArray> palette_ta = palette.As<Uint8ClampedArray>();
|
||||
pngargs.nPaletteColors = palette_ta->Length();
|
||||
if (pngargs.nPaletteColors % 4 != 0) {
|
||||
throw "Palette length must be a multiple of 4.";
|
||||
}
|
||||
pngargs.nPaletteColors /= 4;
|
||||
Nan::TypedArrayContents<uint8_t> _paletteColors(palette_ta);
|
||||
pngargs.palette = *_paletteColors;
|
||||
// Optional background color index:
|
||||
Local<Value> backgroundIndexVal = Nan::Get(obj, Nan::New("backgroundIndex").ToLocalChecked()).ToLocalChecked();
|
||||
if (backgroundIndexVal->IsUint32()) {
|
||||
pngargs.backgroundIndex = static_cast<uint8_t>(Nan::To<uint32_t>(backgroundIndexVal).FromMaybe(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
static void parseJPEGArgs(Local<Value> arg, JpegClosure& jpegargs) {
|
||||
// "If Type(quality) is not Number, or if quality is outside that range, the
|
||||
// user agent must use its default quality value, as if the quality argument
|
||||
// had not been given." - 4.12.5.5
|
||||
if (arg->IsObject()) {
|
||||
Local<Object> obj = Nan::To<Object>(arg).ToLocalChecked();
|
||||
|
||||
Local<Value> qual = Nan::Get(obj, Nan::New("quality").ToLocalChecked()).ToLocalChecked();
|
||||
if (qual->IsNumber()) {
|
||||
double quality = Nan::To<double>(qual).FromMaybe(0);
|
||||
if (quality >= 0.0 && quality <= 1.0) {
|
||||
jpegargs.quality = static_cast<uint32_t>(100.0 * quality);
|
||||
}
|
||||
}
|
||||
|
||||
Local<Value> chroma = Nan::Get(obj, Nan::New("chromaSubsampling").ToLocalChecked()).ToLocalChecked();
|
||||
if (chroma->IsBoolean()) {
|
||||
bool subsample = Nan::To<bool>(chroma).FromMaybe(0);
|
||||
jpegargs.chromaSubsampling = subsample ? 2 : 1;
|
||||
} else if (chroma->IsNumber()) {
|
||||
jpegargs.chromaSubsampling = Nan::To<uint32_t>(chroma).FromMaybe(0);
|
||||
}
|
||||
|
||||
Local<Value> progressive = Nan::Get(obj, Nan::New("progressive").ToLocalChecked()).ToLocalChecked();
|
||||
if (!progressive->IsUndefined()) {
|
||||
jpegargs.progressive = Nan::To<bool>(progressive).FromMaybe(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 16, 0)
|
||||
|
||||
static inline void setPdfMetaStr(cairo_surface_t* surf, Local<Object> opts,
|
||||
cairo_pdf_metadata_t t, const char* pName) {
|
||||
auto propName = Nan::New(pName).ToLocalChecked();
|
||||
auto propValue = Nan::Get(opts, propName).ToLocalChecked();
|
||||
if (propValue->IsString()) {
|
||||
// (copies char data)
|
||||
cairo_pdf_surface_set_metadata(surf, t, *Nan::Utf8String(propValue));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void setPdfMetaDate(cairo_surface_t* surf, Local<Object> opts,
|
||||
cairo_pdf_metadata_t t, const char* pName) {
|
||||
auto propName = Nan::New(pName).ToLocalChecked();
|
||||
auto propValue = Nan::Get(opts, propName).ToLocalChecked();
|
||||
if (propValue->IsDate()) {
|
||||
auto date = static_cast<time_t>(propValue.As<v8::Date>()->ValueOf() / 1000); // ms -> s
|
||||
char buf[sizeof "2011-10-08T07:07:09Z"];
|
||||
strftime(buf, sizeof buf, "%FT%TZ", gmtime(&date));
|
||||
cairo_pdf_surface_set_metadata(surf, t, buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void setPdfMetadata(Canvas* canvas, Local<Object> opts) {
|
||||
cairo_surface_t* surf = canvas->surface();
|
||||
|
||||
setPdfMetaStr(surf, opts, CAIRO_PDF_METADATA_TITLE, "title");
|
||||
setPdfMetaStr(surf, opts, CAIRO_PDF_METADATA_AUTHOR, "author");
|
||||
setPdfMetaStr(surf, opts, CAIRO_PDF_METADATA_SUBJECT, "subject");
|
||||
setPdfMetaStr(surf, opts, CAIRO_PDF_METADATA_KEYWORDS, "keywords");
|
||||
setPdfMetaStr(surf, opts, CAIRO_PDF_METADATA_CREATOR, "creator");
|
||||
setPdfMetaDate(surf, opts, CAIRO_PDF_METADATA_CREATE_DATE, "creationDate");
|
||||
setPdfMetaDate(surf, opts, CAIRO_PDF_METADATA_MOD_DATE, "modDate");
|
||||
}
|
||||
|
||||
#endif // CAIRO 16+
|
||||
|
||||
/*
|
||||
* Converts/encodes data to a Buffer. Async when a callback function is passed.
|
||||
|
||||
* PDF canvases:
|
||||
(any) => Buffer
|
||||
("application/pdf", config) => Buffer
|
||||
|
||||
* SVG canvases:
|
||||
(any) => Buffer
|
||||
|
||||
* ARGB data:
|
||||
("raw") => Buffer
|
||||
|
||||
* PNG-encoded
|
||||
() => Buffer
|
||||
(undefined|"image/png", {compressionLevel?: number, filter?: number}) => Buffer
|
||||
((err: null|Error, buffer) => any)
|
||||
((err: null|Error, buffer) => any, undefined|"image/png", {compressionLevel?: number, filter?: number})
|
||||
|
||||
* JPEG-encoded
|
||||
("image/jpeg") => Buffer
|
||||
("image/jpeg", {quality?: number, progressive?: Boolean, chromaSubsampling?: Boolean|number}) => Buffer
|
||||
((err: null|Error, buffer) => any, "image/jpeg")
|
||||
((err: null|Error, buffer) => any, "image/jpeg", {quality?: number, progressive?: Boolean, chromaSubsampling?: Boolean|number})
|
||||
*/
|
||||
|
||||
NAN_METHOD(Canvas::ToBuffer) {
|
||||
cairo_status_t status;
|
||||
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
|
||||
|
||||
// Vector canvases, sync only
|
||||
const std::string name = canvas->backend()->getName();
|
||||
if (name == "pdf" || name == "svg") {
|
||||
// mime type may be present, but it's not checked
|
||||
PdfSvgClosure* closure;
|
||||
if (name == "pdf") {
|
||||
closure = static_cast<PdfBackend*>(canvas->backend())->closure();
|
||||
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 16, 0)
|
||||
if (info[1]->IsObject()) { // toBuffer("application/pdf", config)
|
||||
setPdfMetadata(canvas, Nan::To<Object>(info[1]).ToLocalChecked());
|
||||
}
|
||||
#endif // CAIRO 16+
|
||||
} else {
|
||||
closure = static_cast<SvgBackend*>(canvas->backend())->closure();
|
||||
}
|
||||
|
||||
cairo_surface_finish(canvas->surface());
|
||||
Local<Object> buf = Nan::CopyBuffer((char*)&closure->vec[0], closure->vec.size()).ToLocalChecked();
|
||||
info.GetReturnValue().Set(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
// Raw ARGB data -- just a memcpy()
|
||||
if (info[0]->StrictEquals(Nan::New<String>("raw").ToLocalChecked())) {
|
||||
cairo_surface_t *surface = canvas->surface();
|
||||
cairo_surface_flush(surface);
|
||||
if (canvas->nBytes() > node::Buffer::kMaxLength) {
|
||||
Nan::ThrowError("Data exceeds maximum buffer length.");
|
||||
return;
|
||||
}
|
||||
const unsigned char *data = cairo_image_surface_get_data(surface);
|
||||
Isolate* iso = Nan::GetCurrentContext()->GetIsolate();
|
||||
Local<Object> buf = node::Buffer::Copy(iso, reinterpret_cast<const char*>(data), canvas->nBytes()).ToLocalChecked();
|
||||
info.GetReturnValue().Set(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
// Sync PNG, default
|
||||
if (info[0]->IsUndefined() || info[0]->StrictEquals(Nan::New<String>("image/png").ToLocalChecked())) {
|
||||
try {
|
||||
PngClosure closure(canvas);
|
||||
parsePNGArgs(info[1], closure);
|
||||
if (closure.nPaletteColors == 0xFFFFFFFF) {
|
||||
Nan::ThrowError("Palette length must be a multiple of 4.");
|
||||
return;
|
||||
}
|
||||
|
||||
Nan::TryCatch try_catch;
|
||||
status = canvas_write_to_png_stream(canvas->surface(), PngClosure::writeVec, &closure);
|
||||
|
||||
if (try_catch.HasCaught()) {
|
||||
try_catch.ReThrow();
|
||||
} else if (status) {
|
||||
throw status;
|
||||
} else {
|
||||
// TODO it's possible to avoid this copy
|
||||
Local<Object> buf = Nan::CopyBuffer((char *)&closure.vec[0], closure.vec.size()).ToLocalChecked();
|
||||
info.GetReturnValue().Set(buf);
|
||||
}
|
||||
} catch (cairo_status_t ex) {
|
||||
Nan::ThrowError(Canvas::Error(ex));
|
||||
} catch (const char* ex) {
|
||||
Nan::ThrowError(ex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Async PNG
|
||||
if (info[0]->IsFunction() &&
|
||||
(info[1]->IsUndefined() || info[1]->StrictEquals(Nan::New<String>("image/png").ToLocalChecked()))) {
|
||||
|
||||
PngClosure* closure;
|
||||
try {
|
||||
closure = new PngClosure(canvas);
|
||||
parsePNGArgs(info[2], *closure);
|
||||
} catch (cairo_status_t ex) {
|
||||
Nan::ThrowError(Canvas::Error(ex));
|
||||
return;
|
||||
} catch (const char* ex) {
|
||||
Nan::ThrowError(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
canvas->Ref();
|
||||
closure->cb.Reset(info[0].As<Function>());
|
||||
|
||||
uv_work_t* req = new uv_work_t;
|
||||
req->data = closure;
|
||||
// Make sure the surface exists since we won't have an isolate context in the async block:
|
||||
canvas->surface();
|
||||
uv_queue_work(uv_default_loop(), req, ToPngBufferAsync, (uv_after_work_cb)ToBufferAsyncAfter);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
// Sync JPEG
|
||||
Local<Value> jpegStr = Nan::New<String>("image/jpeg").ToLocalChecked();
|
||||
if (info[0]->StrictEquals(jpegStr)) {
|
||||
try {
|
||||
JpegClosure closure(canvas);
|
||||
parseJPEGArgs(info[1], closure);
|
||||
|
||||
Nan::TryCatch try_catch;
|
||||
write_to_jpeg_buffer(canvas->surface(), &closure);
|
||||
|
||||
if (try_catch.HasCaught()) {
|
||||
try_catch.ReThrow();
|
||||
} else {
|
||||
// TODO it's possible to avoid this copy.
|
||||
Local<Object> buf = Nan::CopyBuffer((char *)&closure.vec[0], closure.vec.size()).ToLocalChecked();
|
||||
info.GetReturnValue().Set(buf);
|
||||
}
|
||||
} catch (cairo_status_t ex) {
|
||||
Nan::ThrowError(Canvas::Error(ex));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Async JPEG
|
||||
if (info[0]->IsFunction() && info[1]->StrictEquals(jpegStr)) {
|
||||
JpegClosure* closure = new JpegClosure(canvas);
|
||||
parseJPEGArgs(info[2], *closure);
|
||||
|
||||
canvas->Ref();
|
||||
closure->cb.Reset(info[0].As<Function>());
|
||||
|
||||
uv_work_t* req = new uv_work_t;
|
||||
req->data = closure;
|
||||
// Make sure the surface exists since we won't have an isolate context in the async block:
|
||||
canvas->surface();
|
||||
uv_queue_work(uv_default_loop(), req, ToJpegBufferAsync, (uv_after_work_cb)ToBufferAsyncAfter);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Canvas::StreamPNG callback.
|
||||
*/
|
||||
|
||||
static cairo_status_t
|
||||
streamPNG(void *c, const uint8_t *data, unsigned len) {
|
||||
Nan::HandleScope scope;
|
||||
Nan::AsyncResource async("canvas:StreamPNG");
|
||||
PngClosure* closure = (PngClosure*) c;
|
||||
Local<Object> buf = Nan::CopyBuffer((char *)data, len).ToLocalChecked();
|
||||
Local<Value> argv[3] = {
|
||||
Nan::Null()
|
||||
, buf
|
||||
, Nan::New<Number>(len) };
|
||||
closure->cb.Call(sizeof argv / sizeof *argv, argv, &async);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stream PNG data synchronously. TODO async
|
||||
* StreamPngSync(this, options: {palette?: Uint8ClampedArray, backgroundIndex?: uint32, compressionLevel: uint32, filters: uint32})
|
||||
*/
|
||||
|
||||
NAN_METHOD(Canvas::StreamPNGSync) {
|
||||
if (!info[0]->IsFunction())
|
||||
return Nan::ThrowTypeError("callback function required");
|
||||
|
||||
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
|
||||
|
||||
PngClosure closure(canvas);
|
||||
parsePNGArgs(info[1], closure);
|
||||
|
||||
closure.cb.Reset(Local<Function>::Cast(info[0]));
|
||||
|
||||
Nan::TryCatch try_catch;
|
||||
|
||||
cairo_status_t status = canvas_write_to_png_stream(canvas->surface(), streamPNG, &closure);
|
||||
|
||||
if (try_catch.HasCaught()) {
|
||||
try_catch.ReThrow();
|
||||
return;
|
||||
} else if (status) {
|
||||
Local<Value> argv[1] = { Canvas::Error(status) };
|
||||
Nan::Call(closure.cb, Nan::GetCurrentContext()->Global(), sizeof argv / sizeof *argv, argv);
|
||||
} else {
|
||||
Local<Value> argv[3] = {
|
||||
Nan::Null()
|
||||
, Nan::Null()
|
||||
, Nan::New<Uint32>(0) };
|
||||
Nan::Call(closure.cb, Nan::GetCurrentContext()->Global(), sizeof argv / sizeof *argv, argv);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
struct PdfStreamInfo {
|
||||
Local<Function> fn;
|
||||
uint32_t len;
|
||||
uint8_t* data;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Canvas::StreamPDF FreeCallback
|
||||
*/
|
||||
|
||||
void stream_pdf_free(char *, void *) {}
|
||||
|
||||
/*
|
||||
* Canvas::StreamPDF callback.
|
||||
*/
|
||||
|
||||
static cairo_status_t
|
||||
streamPDF(void *c, const uint8_t *data, unsigned len) {
|
||||
Nan::HandleScope scope;
|
||||
Nan::AsyncResource async("canvas:StreamPDF");
|
||||
PdfStreamInfo* streaminfo = static_cast<PdfStreamInfo*>(c);
|
||||
// TODO this is technically wrong, we're returning a pointer to the data in a
|
||||
// vector in a class with automatic storage duration. If the canvas goes out
|
||||
// of scope while we're in the handler, a use-after-free could happen.
|
||||
Local<Object> buf = Nan::NewBuffer(const_cast<char *>(reinterpret_cast<const char *>(data)), len, stream_pdf_free, 0).ToLocalChecked();
|
||||
Local<Value> argv[3] = {
|
||||
Nan::Null()
|
||||
, buf
|
||||
, Nan::New<Number>(len) };
|
||||
async.runInAsyncScope(Nan::GetCurrentContext()->Global(), streaminfo->fn, sizeof argv / sizeof *argv, argv);
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
cairo_status_t canvas_write_to_pdf_stream(cairo_surface_t *surface, cairo_write_func_t write_func, PdfStreamInfo* streaminfo) {
|
||||
size_t whole_chunks = streaminfo->len / PAGE_SIZE;
|
||||
size_t remainder = streaminfo->len - whole_chunks * PAGE_SIZE;
|
||||
|
||||
for (size_t i = 0; i < whole_chunks; ++i) {
|
||||
write_func(streaminfo, &streaminfo->data[i * PAGE_SIZE], PAGE_SIZE);
|
||||
}
|
||||
|
||||
if (remainder) {
|
||||
write_func(streaminfo, &streaminfo->data[whole_chunks * PAGE_SIZE], remainder);
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stream PDF data synchronously.
|
||||
*/
|
||||
|
||||
NAN_METHOD(Canvas::StreamPDFSync) {
|
||||
if (!info[0]->IsFunction())
|
||||
return Nan::ThrowTypeError("callback function required");
|
||||
|
||||
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.Holder());
|
||||
|
||||
if (canvas->backend()->getName() != "pdf")
|
||||
return Nan::ThrowTypeError("wrong canvas type");
|
||||
|
||||
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 16, 0)
|
||||
if (info[1]->IsObject()) {
|
||||
setPdfMetadata(canvas, Nan::To<Object>(info[1]).ToLocalChecked());
|
||||
}
|
||||
#endif
|
||||
|
||||
cairo_surface_finish(canvas->surface());
|
||||
|
||||
PdfSvgClosure* closure = static_cast<PdfBackend*>(canvas->backend())->closure();
|
||||
Local<Function> fn = info[0].As<Function>();
|
||||
PdfStreamInfo streaminfo;
|
||||
streaminfo.fn = fn;
|
||||
streaminfo.data = &closure->vec[0];
|
||||
streaminfo.len = closure->vec.size();
|
||||
|
||||
Nan::TryCatch try_catch;
|
||||
|
||||
cairo_status_t status = canvas_write_to_pdf_stream(canvas->surface(), streamPDF, &streaminfo);
|
||||
|
||||
if (try_catch.HasCaught()) {
|
||||
try_catch.ReThrow();
|
||||
} else if (status) {
|
||||
Local<Value> error = Canvas::Error(status);
|
||||
Nan::Call(fn, Nan::GetCurrentContext()->Global(), 1, &error);
|
||||
} else {
|
||||
Local<Value> argv[3] = {
|
||||
Nan::Null()
|
||||
, Nan::Null()
|
||||
, Nan::New<Uint32>(0) };
|
||||
Nan::Call(fn, Nan::GetCurrentContext()->Global(), sizeof argv / sizeof *argv, argv);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Stream JPEG data synchronously.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
static uint32_t getSafeBufSize(Canvas* canvas) {
|
||||
// Don't allow the buffer size to exceed the size of the canvas (#674)
|
||||
// TODO not sure if this is really correct, but it fixed #674
|
||||
return (std::min)(canvas->getWidth() * canvas->getHeight() * 4, static_cast<int>(PAGE_SIZE));
|
||||
}
|
||||
|
||||
NAN_METHOD(Canvas::StreamJPEGSync) {
|
||||
if (!info[1]->IsFunction())
|
||||
return Nan::ThrowTypeError("callback function required");
|
||||
|
||||
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
|
||||
JpegClosure closure(canvas);
|
||||
parseJPEGArgs(info[0], closure);
|
||||
closure.cb.Reset(Local<Function>::Cast(info[1]));
|
||||
|
||||
Nan::TryCatch try_catch;
|
||||
uint32_t bufsize = getSafeBufSize(canvas);
|
||||
write_to_jpeg_stream(canvas->surface(), bufsize, &closure);
|
||||
|
||||
if (try_catch.HasCaught()) {
|
||||
try_catch.ReThrow();
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *
|
||||
str_value(Local<Value> val, const char *fallback, bool can_be_number) {
|
||||
if (val->IsString() || (can_be_number && val->IsNumber())) {
|
||||
return strdup(*Nan::Utf8String(val));
|
||||
} else if (fallback) {
|
||||
return strdup(fallback);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
NAN_METHOD(Canvas::RegisterFont) {
|
||||
if (!info[0]->IsString()) {
|
||||
return Nan::ThrowError("Wrong argument type");
|
||||
} else if (!info[1]->IsObject()) {
|
||||
return Nan::ThrowError(GENERIC_FACE_ERROR);
|
||||
}
|
||||
|
||||
Nan::Utf8String filePath(info[0]);
|
||||
PangoFontDescription *sys_desc = get_pango_font_description((unsigned char *) *filePath);
|
||||
|
||||
if (!sys_desc) return Nan::ThrowError("Could not parse font file");
|
||||
|
||||
PangoFontDescription *user_desc = pango_font_description_new();
|
||||
|
||||
// now check the attrs, there are many ways to be wrong
|
||||
Local<Object> js_user_desc = Nan::To<Object>(info[1]).ToLocalChecked();
|
||||
Local<String> family_prop = Nan::New<String>("family").ToLocalChecked();
|
||||
Local<String> weight_prop = Nan::New<String>("weight").ToLocalChecked();
|
||||
Local<String> style_prop = Nan::New<String>("style").ToLocalChecked();
|
||||
|
||||
char *family = str_value(Nan::Get(js_user_desc, family_prop).ToLocalChecked(), NULL, false);
|
||||
char *weight = str_value(Nan::Get(js_user_desc, weight_prop).ToLocalChecked(), "normal", true);
|
||||
char *style = str_value(Nan::Get(js_user_desc, style_prop).ToLocalChecked(), "normal", false);
|
||||
|
||||
if (family && weight && style) {
|
||||
pango_font_description_set_weight(user_desc, Canvas::GetWeightFromCSSString(weight));
|
||||
pango_font_description_set_style(user_desc, Canvas::GetStyleFromCSSString(style));
|
||||
pango_font_description_set_family(user_desc, family);
|
||||
|
||||
auto found = std::find_if(font_face_list.begin(), font_face_list.end(), [&](FontFace& f) {
|
||||
return pango_font_description_equal(f.sys_desc, sys_desc);
|
||||
});
|
||||
|
||||
if (found != font_face_list.end()) {
|
||||
pango_font_description_free(found->user_desc);
|
||||
found->user_desc = user_desc;
|
||||
} else if (register_font((unsigned char *) *filePath)) {
|
||||
FontFace face;
|
||||
face.user_desc = user_desc;
|
||||
face.sys_desc = sys_desc;
|
||||
strncpy((char *)face.file_path, (char *) *filePath, 1023);
|
||||
font_face_list.push_back(face);
|
||||
} else {
|
||||
pango_font_description_free(user_desc);
|
||||
Nan::ThrowError("Could not load font to the system's font host");
|
||||
}
|
||||
} else {
|
||||
pango_font_description_free(user_desc);
|
||||
Nan::ThrowError(GENERIC_FACE_ERROR);
|
||||
}
|
||||
|
||||
free(family);
|
||||
free(weight);
|
||||
free(style);
|
||||
}
|
||||
|
||||
NAN_METHOD(Canvas::DeregisterAllFonts) {
|
||||
// Unload all fonts from pango to free up memory
|
||||
bool success = true;
|
||||
|
||||
std::for_each(font_face_list.begin(), font_face_list.end(), [&](FontFace& f) {
|
||||
if (!deregister_font( (unsigned char *)f.file_path )) success = false;
|
||||
pango_font_description_free(f.user_desc);
|
||||
pango_font_description_free(f.sys_desc);
|
||||
});
|
||||
|
||||
font_face_list.clear();
|
||||
if (!success) Nan::ThrowError("Could not deregister one or more fonts");
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize cairo surface.
|
||||
*/
|
||||
|
||||
Canvas::Canvas(Backend* backend) : ObjectWrap() {
|
||||
_backend = backend;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy cairo surface.
|
||||
*/
|
||||
|
||||
Canvas::~Canvas() {
|
||||
if (_backend != NULL) {
|
||||
delete _backend;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a PangoStyle from a CSS string (like "italic")
|
||||
*/
|
||||
|
||||
PangoStyle
|
||||
Canvas::GetStyleFromCSSString(const char *style) {
|
||||
PangoStyle s = PANGO_STYLE_NORMAL;
|
||||
|
||||
if (strlen(style) > 0) {
|
||||
if (0 == strcmp("italic", style)) {
|
||||
s = PANGO_STYLE_ITALIC;
|
||||
} else if (0 == strcmp("oblique", style)) {
|
||||
s = PANGO_STYLE_OBLIQUE;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a PangoWeight from a CSS string ("bold", "100", etc)
|
||||
*/
|
||||
|
||||
PangoWeight
|
||||
Canvas::GetWeightFromCSSString(const char *weight) {
|
||||
PangoWeight w = PANGO_WEIGHT_NORMAL;
|
||||
|
||||
if (strlen(weight) > 0) {
|
||||
if (0 == strcmp("bold", weight)) {
|
||||
w = PANGO_WEIGHT_BOLD;
|
||||
} else if (0 == strcmp("100", weight)) {
|
||||
w = PANGO_WEIGHT_THIN;
|
||||
} else if (0 == strcmp("200", weight)) {
|
||||
w = PANGO_WEIGHT_ULTRALIGHT;
|
||||
} else if (0 == strcmp("300", weight)) {
|
||||
w = PANGO_WEIGHT_LIGHT;
|
||||
} else if (0 == strcmp("400", weight)) {
|
||||
w = PANGO_WEIGHT_NORMAL;
|
||||
} else if (0 == strcmp("500", weight)) {
|
||||
w = PANGO_WEIGHT_MEDIUM;
|
||||
} else if (0 == strcmp("600", weight)) {
|
||||
w = PANGO_WEIGHT_SEMIBOLD;
|
||||
} else if (0 == strcmp("700", weight)) {
|
||||
w = PANGO_WEIGHT_BOLD;
|
||||
} else if (0 == strcmp("800", weight)) {
|
||||
w = PANGO_WEIGHT_ULTRABOLD;
|
||||
} else if (0 == strcmp("900", weight)) {
|
||||
w = PANGO_WEIGHT_HEAVY;
|
||||
}
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a user description, return a description that will select the
|
||||
* font either from the system or @font-face
|
||||
*/
|
||||
|
||||
PangoFontDescription *
|
||||
Canvas::ResolveFontDescription(const PangoFontDescription *desc) {
|
||||
// One of the user-specified families could map to multiple SFNT family names
|
||||
// if someone registered two different fonts under the same family name.
|
||||
// https://drafts.csswg.org/css-fonts-3/#font-style-matching
|
||||
FontFace best;
|
||||
istringstream families(pango_font_description_get_family(desc));
|
||||
unordered_set<string> seen_families;
|
||||
string resolved_families;
|
||||
bool first = true;
|
||||
|
||||
for (string family; getline(families, family, ','); ) {
|
||||
string renamed_families;
|
||||
for (auto& ff : font_face_list) {
|
||||
string pangofamily = string(pango_font_description_get_family(ff.user_desc));
|
||||
if (streq_casein(family, pangofamily)) {
|
||||
const char* sys_desc_family_name = pango_font_description_get_family(ff.sys_desc);
|
||||
bool unseen = seen_families.find(sys_desc_family_name) == seen_families.end();
|
||||
bool better = best.user_desc == nullptr || pango_font_description_better_match(desc, best.user_desc, ff.user_desc);
|
||||
|
||||
// Avoid sending duplicate SFNT font names due to a bug in Pango for macOS:
|
||||
// https://bugzilla.gnome.org/show_bug.cgi?id=762873
|
||||
if (unseen) {
|
||||
seen_families.insert(sys_desc_family_name);
|
||||
|
||||
if (better) {
|
||||
renamed_families = string(sys_desc_family_name) + (renamed_families.size() ? "," : "") + renamed_families;
|
||||
} else {
|
||||
renamed_families = renamed_families + (renamed_families.size() ? "," : "") + sys_desc_family_name;
|
||||
}
|
||||
}
|
||||
|
||||
if (first && better) best = ff;
|
||||
}
|
||||
}
|
||||
|
||||
if (resolved_families.size()) resolved_families += ',';
|
||||
resolved_families += renamed_families.size() ? renamed_families : family;
|
||||
first = false;
|
||||
}
|
||||
|
||||
PangoFontDescription* ret = pango_font_description_copy(best.sys_desc ? best.sys_desc : desc);
|
||||
pango_font_description_set_family(ret, resolved_families.c_str());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-alloc the surface, destroying the previous.
|
||||
*/
|
||||
|
||||
void
|
||||
Canvas::resurface(Local<Object> canvas) {
|
||||
Nan::HandleScope scope;
|
||||
Local<Value> context;
|
||||
|
||||
backend()->recreateSurface();
|
||||
|
||||
// Reset context
|
||||
context = Nan::Get(canvas, Nan::New<String>("context").ToLocalChecked()).ToLocalChecked();
|
||||
if (!context->IsUndefined()) {
|
||||
Context2d *context2d = ObjectWrap::Unwrap<Context2d>(Nan::To<Object>(context).ToLocalChecked());
|
||||
cairo_t *prev = context2d->context();
|
||||
context2d->setContext(createCairoContext());
|
||||
context2d->resetState();
|
||||
cairo_destroy(prev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around cairo_create()
|
||||
* (do not call cairo_create directly, call this instead)
|
||||
*/
|
||||
cairo_t*
|
||||
Canvas::createCairoContext() {
|
||||
cairo_t* ret = cairo_create(surface());
|
||||
cairo_set_line_width(ret, 1); // Cairo defaults to 2
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct an Error from the given cairo status.
|
||||
*/
|
||||
|
||||
Local<Value>
|
||||
Canvas::Error(cairo_status_t status) {
|
||||
return Exception::Error(Nan::New<String>(cairo_status_to_string(status)).ToLocalChecked());
|
||||
}
|
||||
|
||||
#undef CHECK_RECEIVER
|
||||
96
npm-packages/mac-v2.4.x/canvas/src/Canvas.h
Normal file
96
npm-packages/mac-v2.4.x/canvas/src/Canvas.h
Normal file
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "backend/Backend.h"
|
||||
#include <cairo.h>
|
||||
#include "dll_visibility.h"
|
||||
#include <nan.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <v8.h>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
|
||||
/*
|
||||
* FontFace describes a font file in terms of one PangoFontDescription that
|
||||
* will resolve to it and one that the user describes it as (like @font-face)
|
||||
*/
|
||||
class FontFace {
|
||||
public:
|
||||
PangoFontDescription *sys_desc = nullptr;
|
||||
PangoFontDescription *user_desc = nullptr;
|
||||
unsigned char file_path[1024];
|
||||
};
|
||||
|
||||
enum text_baseline_t : uint8_t {
|
||||
TEXT_BASELINE_ALPHABETIC = 0,
|
||||
TEXT_BASELINE_TOP = 1,
|
||||
TEXT_BASELINE_BOTTOM = 2,
|
||||
TEXT_BASELINE_MIDDLE = 3,
|
||||
TEXT_BASELINE_IDEOGRAPHIC = 4,
|
||||
TEXT_BASELINE_HANGING = 5
|
||||
};
|
||||
|
||||
enum text_align_t : int8_t {
|
||||
TEXT_ALIGNMENT_LEFT = -1,
|
||||
TEXT_ALIGNMENT_CENTER = 0,
|
||||
TEXT_ALIGNMENT_RIGHT = 1,
|
||||
// Currently same as LEFT and RIGHT without RTL support:
|
||||
TEXT_ALIGNMENT_START = -2,
|
||||
TEXT_ALIGNMENT_END = 2
|
||||
};
|
||||
|
||||
enum canvas_draw_mode_t : uint8_t {
|
||||
TEXT_DRAW_PATHS,
|
||||
TEXT_DRAW_GLYPHS
|
||||
};
|
||||
|
||||
/*
|
||||
* Canvas.
|
||||
*/
|
||||
|
||||
class Canvas: public Nan::ObjectWrap {
|
||||
public:
|
||||
static Nan::Persistent<v8::FunctionTemplate> constructor;
|
||||
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
|
||||
static NAN_METHOD(New);
|
||||
static NAN_METHOD(ToBuffer);
|
||||
static NAN_GETTER(GetType);
|
||||
static NAN_GETTER(GetStride);
|
||||
static NAN_GETTER(GetWidth);
|
||||
static NAN_GETTER(GetHeight);
|
||||
static NAN_SETTER(SetWidth);
|
||||
static NAN_SETTER(SetHeight);
|
||||
static NAN_METHOD(StreamPNGSync);
|
||||
static NAN_METHOD(StreamPDFSync);
|
||||
static NAN_METHOD(StreamJPEGSync);
|
||||
static NAN_METHOD(RegisterFont);
|
||||
static NAN_METHOD(DeregisterAllFonts);
|
||||
static v8::Local<v8::Value> Error(cairo_status_t status);
|
||||
static void ToPngBufferAsync(uv_work_t *req);
|
||||
static void ToJpegBufferAsync(uv_work_t *req);
|
||||
static void ToBufferAsyncAfter(uv_work_t *req);
|
||||
static PangoWeight GetWeightFromCSSString(const char *weight);
|
||||
static PangoStyle GetStyleFromCSSString(const char *style);
|
||||
static PangoFontDescription *ResolveFontDescription(const PangoFontDescription *desc);
|
||||
|
||||
DLL_PUBLIC inline Backend* backend() { return _backend; }
|
||||
DLL_PUBLIC inline cairo_surface_t* surface(){ return backend()->getSurface(); }
|
||||
cairo_t* createCairoContext();
|
||||
|
||||
DLL_PUBLIC inline uint8_t *data(){ return cairo_image_surface_get_data(surface()); }
|
||||
DLL_PUBLIC inline int stride(){ return cairo_image_surface_get_stride(surface()); }
|
||||
DLL_PUBLIC inline std::size_t nBytes(){
|
||||
return static_cast<std::size_t>(getHeight()) * stride();
|
||||
}
|
||||
|
||||
DLL_PUBLIC inline int getWidth() { return backend()->getWidth(); }
|
||||
DLL_PUBLIC inline int getHeight() { return backend()->getHeight(); }
|
||||
|
||||
Canvas(Backend* backend);
|
||||
void resurface(v8::Local<v8::Object> canvas);
|
||||
|
||||
private:
|
||||
~Canvas();
|
||||
Backend* _backend;
|
||||
};
|
||||
23
npm-packages/mac-v2.4.x/canvas/src/CanvasError.h
Normal file
23
npm-packages/mac-v2.4.x/canvas/src/CanvasError.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class CanvasError {
|
||||
public:
|
||||
std::string message;
|
||||
std::string syscall;
|
||||
std::string path;
|
||||
int cerrno = 0;
|
||||
void set(const char* iMessage = NULL, const char* iSyscall = NULL, int iErrno = 0, const char* iPath = NULL) {
|
||||
if (iMessage) message.assign(iMessage);
|
||||
if (iSyscall) syscall.assign(iSyscall);
|
||||
cerrno = iErrno;
|
||||
if (iPath) path.assign(iPath);
|
||||
}
|
||||
void reset() {
|
||||
message.clear();
|
||||
syscall.clear();
|
||||
path.clear();
|
||||
cerrno = 0;
|
||||
}
|
||||
};
|
||||
123
npm-packages/mac-v2.4.x/canvas/src/CanvasGradient.cc
Normal file
123
npm-packages/mac-v2.4.x/canvas/src/CanvasGradient.cc
Normal file
@@ -0,0 +1,123 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#include "CanvasGradient.h"
|
||||
|
||||
#include "Canvas.h"
|
||||
#include "color.h"
|
||||
|
||||
using namespace v8;
|
||||
|
||||
Nan::Persistent<FunctionTemplate> Gradient::constructor;
|
||||
|
||||
/*
|
||||
* Initialize CanvasGradient.
|
||||
*/
|
||||
|
||||
void
|
||||
Gradient::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
// Constructor
|
||||
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Gradient::New);
|
||||
constructor.Reset(ctor);
|
||||
ctor->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
ctor->SetClassName(Nan::New("CanvasGradient").ToLocalChecked());
|
||||
|
||||
// Prototype
|
||||
Nan::SetPrototypeMethod(ctor, "addColorStop", AddColorStop);
|
||||
Local<Context> ctx = Nan::GetCurrentContext();
|
||||
Nan::Set(target,
|
||||
Nan::New("CanvasGradient").ToLocalChecked(),
|
||||
ctor->GetFunction(ctx).ToLocalChecked());
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a new CanvasGradient.
|
||||
*/
|
||||
|
||||
NAN_METHOD(Gradient::New) {
|
||||
if (!info.IsConstructCall()) {
|
||||
return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
|
||||
}
|
||||
|
||||
// Linear
|
||||
if (4 == info.Length()) {
|
||||
Gradient *grad = new Gradient(
|
||||
Nan::To<double>(info[0]).FromMaybe(0)
|
||||
, Nan::To<double>(info[1]).FromMaybe(0)
|
||||
, Nan::To<double>(info[2]).FromMaybe(0)
|
||||
, Nan::To<double>(info[3]).FromMaybe(0));
|
||||
grad->Wrap(info.This());
|
||||
info.GetReturnValue().Set(info.This());
|
||||
return;
|
||||
}
|
||||
|
||||
// Radial
|
||||
if (6 == info.Length()) {
|
||||
Gradient *grad = new Gradient(
|
||||
Nan::To<double>(info[0]).FromMaybe(0)
|
||||
, Nan::To<double>(info[1]).FromMaybe(0)
|
||||
, Nan::To<double>(info[2]).FromMaybe(0)
|
||||
, Nan::To<double>(info[3]).FromMaybe(0)
|
||||
, Nan::To<double>(info[4]).FromMaybe(0)
|
||||
, Nan::To<double>(info[5]).FromMaybe(0));
|
||||
grad->Wrap(info.This());
|
||||
info.GetReturnValue().Set(info.This());
|
||||
return;
|
||||
}
|
||||
|
||||
return Nan::ThrowTypeError("invalid arguments");
|
||||
}
|
||||
|
||||
/*
|
||||
* Add color stop.
|
||||
*/
|
||||
|
||||
NAN_METHOD(Gradient::AddColorStop) {
|
||||
if (!info[0]->IsNumber())
|
||||
return Nan::ThrowTypeError("offset required");
|
||||
if (!info[1]->IsString())
|
||||
return Nan::ThrowTypeError("color string required");
|
||||
|
||||
Gradient *grad = Nan::ObjectWrap::Unwrap<Gradient>(info.This());
|
||||
short ok;
|
||||
Nan::Utf8String str(info[1]);
|
||||
uint32_t rgba = rgba_from_string(*str, &ok);
|
||||
|
||||
if (ok) {
|
||||
rgba_t color = rgba_create(rgba);
|
||||
cairo_pattern_add_color_stop_rgba(
|
||||
grad->pattern()
|
||||
, Nan::To<double>(info[0]).FromMaybe(0)
|
||||
, color.r
|
||||
, color.g
|
||||
, color.b
|
||||
, color.a);
|
||||
} else {
|
||||
return Nan::ThrowTypeError("parse color failed");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize linear gradient.
|
||||
*/
|
||||
|
||||
Gradient::Gradient(double x0, double y0, double x1, double y1) {
|
||||
_pattern = cairo_pattern_create_linear(x0, y0, x1, y1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize radial gradient.
|
||||
*/
|
||||
|
||||
Gradient::Gradient(double x0, double y0, double r0, double x1, double y1, double r1) {
|
||||
_pattern = cairo_pattern_create_radial(x0, y0, r0, x1, y1, r1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the pattern.
|
||||
*/
|
||||
|
||||
Gradient::~Gradient() {
|
||||
cairo_pattern_destroy(_pattern);
|
||||
}
|
||||
22
npm-packages/mac-v2.4.x/canvas/src/CanvasGradient.h
Normal file
22
npm-packages/mac-v2.4.x/canvas/src/CanvasGradient.h
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nan.h>
|
||||
#include <v8.h>
|
||||
#include <cairo.h>
|
||||
|
||||
class Gradient: public Nan::ObjectWrap {
|
||||
public:
|
||||
static Nan::Persistent<v8::FunctionTemplate> constructor;
|
||||
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
|
||||
static NAN_METHOD(New);
|
||||
static NAN_METHOD(AddColorStop);
|
||||
Gradient(double x0, double y0, double x1, double y1);
|
||||
Gradient(double x0, double y0, double r0, double x1, double y1, double r1);
|
||||
inline cairo_pattern_t *pattern(){ return _pattern; }
|
||||
|
||||
private:
|
||||
~Gradient();
|
||||
cairo_pattern_t *_pattern;
|
||||
};
|
||||
136
npm-packages/mac-v2.4.x/canvas/src/CanvasPattern.cc
Normal file
136
npm-packages/mac-v2.4.x/canvas/src/CanvasPattern.cc
Normal file
@@ -0,0 +1,136 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#include "CanvasPattern.h"
|
||||
|
||||
#include "Canvas.h"
|
||||
#include "Image.h"
|
||||
|
||||
using namespace v8;
|
||||
|
||||
const cairo_user_data_key_t *pattern_repeat_key;
|
||||
|
||||
Nan::Persistent<FunctionTemplate> Pattern::constructor;
|
||||
Nan::Persistent<Function> Pattern::_DOMMatrix;
|
||||
|
||||
/*
|
||||
* Initialize CanvasPattern.
|
||||
*/
|
||||
|
||||
void
|
||||
Pattern::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
// Constructor
|
||||
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Pattern::New);
|
||||
constructor.Reset(ctor);
|
||||
ctor->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
ctor->SetClassName(Nan::New("CanvasPattern").ToLocalChecked());
|
||||
Nan::SetPrototypeMethod(ctor, "setTransform", SetTransform);
|
||||
|
||||
// Prototype
|
||||
Local<Context> ctx = Nan::GetCurrentContext();
|
||||
Nan::Set(target, Nan::New("CanvasPattern").ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked());
|
||||
Nan::Set(target, Nan::New("CanvasPatternInit").ToLocalChecked(), Nan::New<Function>(SaveExternalModules));
|
||||
}
|
||||
|
||||
/*
|
||||
* Save some external modules as private references.
|
||||
*/
|
||||
|
||||
NAN_METHOD(Pattern::SaveExternalModules) {
|
||||
_DOMMatrix.Reset(Nan::To<Function>(info[0]).ToLocalChecked());
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a new CanvasPattern.
|
||||
*/
|
||||
|
||||
NAN_METHOD(Pattern::New) {
|
||||
if (!info.IsConstructCall()) {
|
||||
return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
|
||||
}
|
||||
|
||||
cairo_surface_t *surface;
|
||||
|
||||
Local<Object> obj = Nan::To<Object>(info[0]).ToLocalChecked();
|
||||
|
||||
// Image
|
||||
if (Nan::New(Image::constructor)->HasInstance(obj)) {
|
||||
Image *img = Nan::ObjectWrap::Unwrap<Image>(obj);
|
||||
if (!img->isComplete()) {
|
||||
return Nan::ThrowError("Image given has not completed loading");
|
||||
}
|
||||
surface = img->surface();
|
||||
|
||||
// Canvas
|
||||
} else if (Nan::New(Canvas::constructor)->HasInstance(obj)) {
|
||||
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(obj);
|
||||
surface = canvas->surface();
|
||||
// Invalid
|
||||
} else {
|
||||
return Nan::ThrowTypeError("Image or Canvas expected");
|
||||
}
|
||||
repeat_type_t repeat = REPEAT;
|
||||
if (0 == strcmp("no-repeat", *Nan::Utf8String(info[1]))) {
|
||||
repeat = NO_REPEAT;
|
||||
} else if (0 == strcmp("repeat-x", *Nan::Utf8String(info[1]))) {
|
||||
repeat = REPEAT_X;
|
||||
} else if (0 == strcmp("repeat-y", *Nan::Utf8String(info[1]))) {
|
||||
repeat = REPEAT_Y;
|
||||
}
|
||||
Pattern *pattern = new Pattern(surface, repeat);
|
||||
pattern->Wrap(info.This());
|
||||
info.GetReturnValue().Set(info.This());
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the pattern-space to user-space transform.
|
||||
*/
|
||||
NAN_METHOD(Pattern::SetTransform) {
|
||||
Pattern *pattern = Nan::ObjectWrap::Unwrap<Pattern>(info.This());
|
||||
Local<Context> ctx = Nan::GetCurrentContext();
|
||||
Local<Object> mat = Nan::To<Object>(info[0]).ToLocalChecked();
|
||||
|
||||
#if NODE_MAJOR_VERSION >= 8
|
||||
if (!mat->InstanceOf(ctx, _DOMMatrix.Get(Isolate::GetCurrent())).ToChecked()) {
|
||||
return Nan::ThrowTypeError("Expected DOMMatrix");
|
||||
}
|
||||
#endif
|
||||
|
||||
cairo_matrix_t matrix;
|
||||
cairo_matrix_init(&matrix,
|
||||
Nan::To<double>(Nan::Get(mat, Nan::New("a").ToLocalChecked()).ToLocalChecked()).FromMaybe(1),
|
||||
Nan::To<double>(Nan::Get(mat, Nan::New("b").ToLocalChecked()).ToLocalChecked()).FromMaybe(0),
|
||||
Nan::To<double>(Nan::Get(mat, Nan::New("c").ToLocalChecked()).ToLocalChecked()).FromMaybe(0),
|
||||
Nan::To<double>(Nan::Get(mat, Nan::New("d").ToLocalChecked()).ToLocalChecked()).FromMaybe(1),
|
||||
Nan::To<double>(Nan::Get(mat, Nan::New("e").ToLocalChecked()).ToLocalChecked()).FromMaybe(0),
|
||||
Nan::To<double>(Nan::Get(mat, Nan::New("f").ToLocalChecked()).ToLocalChecked()).FromMaybe(0)
|
||||
);
|
||||
|
||||
cairo_matrix_invert(&matrix);
|
||||
cairo_pattern_set_matrix(pattern->_pattern, &matrix);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize pattern.
|
||||
*/
|
||||
|
||||
Pattern::Pattern(cairo_surface_t *surface, repeat_type_t repeat) {
|
||||
_pattern = cairo_pattern_create_for_surface(surface);
|
||||
_repeat = repeat;
|
||||
cairo_pattern_set_user_data(_pattern, pattern_repeat_key, &_repeat, NULL);
|
||||
}
|
||||
|
||||
repeat_type_t Pattern::get_repeat_type_for_cairo_pattern(cairo_pattern_t *pattern) {
|
||||
void *ud = cairo_pattern_get_user_data(pattern, pattern_repeat_key);
|
||||
return *reinterpret_cast<repeat_type_t*>(ud);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the pattern.
|
||||
*/
|
||||
|
||||
Pattern::~Pattern() {
|
||||
cairo_pattern_destroy(_pattern);
|
||||
}
|
||||
37
npm-packages/mac-v2.4.x/canvas/src/CanvasPattern.h
Normal file
37
npm-packages/mac-v2.4.x/canvas/src/CanvasPattern.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2011 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cairo.h>
|
||||
#include <nan.h>
|
||||
#include <v8.h>
|
||||
|
||||
/*
|
||||
* Canvas types.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
NO_REPEAT, // match CAIRO_EXTEND_NONE
|
||||
REPEAT, // match CAIRO_EXTEND_REPEAT
|
||||
REPEAT_X, // needs custom processing
|
||||
REPEAT_Y // needs custom processing
|
||||
} repeat_type_t;
|
||||
|
||||
extern const cairo_user_data_key_t *pattern_repeat_key;
|
||||
|
||||
class Pattern: public Nan::ObjectWrap {
|
||||
public:
|
||||
static Nan::Persistent<v8::FunctionTemplate> constructor;
|
||||
static Nan::Persistent<v8::Function> _DOMMatrix;
|
||||
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
|
||||
static NAN_METHOD(New);
|
||||
static NAN_METHOD(SaveExternalModules);
|
||||
static NAN_METHOD(SetTransform);
|
||||
static repeat_type_t get_repeat_type_for_cairo_pattern(cairo_pattern_t *pattern);
|
||||
Pattern(cairo_surface_t *surface, repeat_type_t repeat);
|
||||
inline cairo_pattern_t *pattern(){ return _pattern; }
|
||||
private:
|
||||
~Pattern();
|
||||
cairo_pattern_t *_pattern;
|
||||
repeat_type_t _repeat;
|
||||
};
|
||||
3360
npm-packages/mac-v2.4.x/canvas/src/CanvasRenderingContext2d.cc
Normal file
3360
npm-packages/mac-v2.4.x/canvas/src/CanvasRenderingContext2d.cc
Normal file
File diff suppressed because it is too large
Load Diff
3381
npm-packages/mac-v2.4.x/canvas/src/CanvasRenderingContext2d.cc.orig
Normal file
3381
npm-packages/mac-v2.4.x/canvas/src/CanvasRenderingContext2d.cc.orig
Normal file
File diff suppressed because it is too large
Load Diff
225
npm-packages/mac-v2.4.x/canvas/src/CanvasRenderingContext2d.h
Normal file
225
npm-packages/mac-v2.4.x/canvas/src/CanvasRenderingContext2d.h
Normal file
@@ -0,0 +1,225 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cairo.h"
|
||||
#include "Canvas.h"
|
||||
#include "color.h"
|
||||
#include "nan.h"
|
||||
#include <pango/pangocairo.h>
|
||||
#include <stack>
|
||||
|
||||
/*
|
||||
* State struct.
|
||||
*
|
||||
* Used in conjunction with Save() / Restore() since
|
||||
* cairo's gstate maintains only a single source pattern at a time.
|
||||
*/
|
||||
|
||||
struct canvas_state_t {
|
||||
rgba_t fill = { 0, 0, 0, 1 };
|
||||
rgba_t stroke = { 0, 0, 0, 1 };
|
||||
rgba_t shadow = { 0, 0, 0, 0 };
|
||||
double shadowOffsetX = 0.;
|
||||
double shadowOffsetY = 0.;
|
||||
cairo_pattern_t* fillPattern = nullptr;
|
||||
cairo_pattern_t* strokePattern = nullptr;
|
||||
cairo_pattern_t* fillGradient = nullptr;
|
||||
cairo_pattern_t* strokeGradient = nullptr;
|
||||
PangoFontDescription* fontDescription = nullptr;
|
||||
std::string font = "10px sans-serif";
|
||||
cairo_filter_t patternQuality = CAIRO_FILTER_GOOD;
|
||||
float globalAlpha = 1.f;
|
||||
int shadowBlur = 0;
|
||||
text_align_t textAlignment = TEXT_ALIGNMENT_LEFT; // TODO default is supposed to be START
|
||||
text_baseline_t textBaseline = TEXT_BASELINE_ALPHABETIC;
|
||||
canvas_draw_mode_t textDrawingMode = TEXT_DRAW_PATHS;
|
||||
bool imageSmoothingEnabled = true;
|
||||
|
||||
canvas_state_t() {
|
||||
fontDescription = pango_font_description_from_string("sans");
|
||||
pango_font_description_set_absolute_size(fontDescription, 10 * PANGO_SCALE);
|
||||
}
|
||||
|
||||
canvas_state_t(const canvas_state_t& other) {
|
||||
fill = other.fill;
|
||||
stroke = other.stroke;
|
||||
patternQuality = other.patternQuality;
|
||||
fillPattern = other.fillPattern;
|
||||
strokePattern = other.strokePattern;
|
||||
fillGradient = other.fillGradient;
|
||||
strokeGradient = other.strokeGradient;
|
||||
globalAlpha = other.globalAlpha;
|
||||
textAlignment = other.textAlignment;
|
||||
textBaseline = other.textBaseline;
|
||||
shadow = other.shadow;
|
||||
shadowBlur = other.shadowBlur;
|
||||
shadowOffsetX = other.shadowOffsetX;
|
||||
shadowOffsetY = other.shadowOffsetY;
|
||||
textDrawingMode = other.textDrawingMode;
|
||||
fontDescription = pango_font_description_copy(other.fontDescription);
|
||||
font = other.font;
|
||||
imageSmoothingEnabled = other.imageSmoothingEnabled;
|
||||
}
|
||||
|
||||
~canvas_state_t() {
|
||||
pango_font_description_free(fontDescription);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Equivalent to a PangoRectangle but holds floats instead of ints
|
||||
* (software pixels are stored here instead of pango units)
|
||||
*
|
||||
* Should be compatible with PANGO_ASCENT, PANGO_LBEARING, etc.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
float x;
|
||||
float y;
|
||||
float width;
|
||||
float height;
|
||||
} float_rectangle;
|
||||
|
||||
class Context2d : public Nan::ObjectWrap {
|
||||
public:
|
||||
std::stack<canvas_state_t> states;
|
||||
canvas_state_t *state;
|
||||
Context2d(Canvas *canvas);
|
||||
static Nan::Persistent<v8::Function> _DOMMatrix;
|
||||
static Nan::Persistent<v8::Function> _parseFont;
|
||||
static Nan::Persistent<v8::FunctionTemplate> constructor;
|
||||
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
|
||||
static NAN_METHOD(New);
|
||||
static NAN_METHOD(SaveExternalModules);
|
||||
static NAN_METHOD(DrawImage);
|
||||
static NAN_METHOD(PutImageData);
|
||||
static NAN_METHOD(Save);
|
||||
static NAN_METHOD(Restore);
|
||||
static NAN_METHOD(Rotate);
|
||||
static NAN_METHOD(Translate);
|
||||
static NAN_METHOD(Scale);
|
||||
static NAN_METHOD(Transform);
|
||||
static NAN_METHOD(GetTransform);
|
||||
static NAN_METHOD(ResetTransform);
|
||||
static NAN_METHOD(SetTransform);
|
||||
static NAN_METHOD(IsPointInPath);
|
||||
static NAN_METHOD(BeginPath);
|
||||
static NAN_METHOD(ClosePath);
|
||||
static NAN_METHOD(AddPage);
|
||||
static NAN_METHOD(Clip);
|
||||
static NAN_METHOD(Fill);
|
||||
static NAN_METHOD(Stroke);
|
||||
static NAN_METHOD(FillText);
|
||||
static NAN_METHOD(StrokeText);
|
||||
static NAN_METHOD(SetFont);
|
||||
static NAN_METHOD(SetFillColor);
|
||||
static NAN_METHOD(SetStrokeColor);
|
||||
static NAN_METHOD(SetStrokePattern);
|
||||
static NAN_METHOD(SetTextAlignment);
|
||||
static NAN_METHOD(SetLineDash);
|
||||
static NAN_METHOD(GetLineDash);
|
||||
static NAN_METHOD(MeasureText);
|
||||
static NAN_METHOD(BezierCurveTo);
|
||||
static NAN_METHOD(QuadraticCurveTo);
|
||||
static NAN_METHOD(LineTo);
|
||||
static NAN_METHOD(MoveTo);
|
||||
static NAN_METHOD(FillRect);
|
||||
static NAN_METHOD(StrokeRect);
|
||||
static NAN_METHOD(ClearRect);
|
||||
static NAN_METHOD(Rect);
|
||||
static NAN_METHOD(RoundRect);
|
||||
static NAN_METHOD(Arc);
|
||||
static NAN_METHOD(ArcTo);
|
||||
static NAN_METHOD(Ellipse);
|
||||
static NAN_METHOD(GetImageData);
|
||||
static NAN_METHOD(CreateImageData);
|
||||
static NAN_METHOD(GetStrokeColor);
|
||||
static NAN_METHOD(CreatePattern);
|
||||
static NAN_METHOD(CreateLinearGradient);
|
||||
static NAN_METHOD(CreateRadialGradient);
|
||||
static NAN_GETTER(GetFormat);
|
||||
static NAN_GETTER(GetPatternQuality);
|
||||
static NAN_GETTER(GetImageSmoothingEnabled);
|
||||
static NAN_GETTER(GetGlobalCompositeOperation);
|
||||
static NAN_GETTER(GetGlobalAlpha);
|
||||
static NAN_GETTER(GetShadowColor);
|
||||
static NAN_GETTER(GetMiterLimit);
|
||||
static NAN_GETTER(GetLineCap);
|
||||
static NAN_GETTER(GetLineJoin);
|
||||
static NAN_GETTER(GetLineWidth);
|
||||
static NAN_GETTER(GetLineDashOffset);
|
||||
static NAN_GETTER(GetShadowOffsetX);
|
||||
static NAN_GETTER(GetShadowOffsetY);
|
||||
static NAN_GETTER(GetShadowBlur);
|
||||
static NAN_GETTER(GetAntiAlias);
|
||||
static NAN_GETTER(GetTextDrawingMode);
|
||||
static NAN_GETTER(GetQuality);
|
||||
static NAN_GETTER(GetCurrentTransform);
|
||||
static NAN_GETTER(GetFillStyle);
|
||||
static NAN_GETTER(GetStrokeStyle);
|
||||
static NAN_GETTER(GetFont);
|
||||
static NAN_GETTER(GetTextBaseline);
|
||||
static NAN_GETTER(GetTextAlign);
|
||||
static NAN_SETTER(SetPatternQuality);
|
||||
static NAN_SETTER(SetImageSmoothingEnabled);
|
||||
static NAN_SETTER(SetGlobalCompositeOperation);
|
||||
static NAN_SETTER(SetGlobalAlpha);
|
||||
static NAN_SETTER(SetShadowColor);
|
||||
static NAN_SETTER(SetMiterLimit);
|
||||
static NAN_SETTER(SetLineCap);
|
||||
static NAN_SETTER(SetLineJoin);
|
||||
static NAN_SETTER(SetLineWidth);
|
||||
static NAN_SETTER(SetLineDashOffset);
|
||||
static NAN_SETTER(SetShadowOffsetX);
|
||||
static NAN_SETTER(SetShadowOffsetY);
|
||||
static NAN_SETTER(SetShadowBlur);
|
||||
static NAN_SETTER(SetAntiAlias);
|
||||
static NAN_SETTER(SetTextDrawingMode);
|
||||
static NAN_SETTER(SetQuality);
|
||||
static NAN_SETTER(SetCurrentTransform);
|
||||
static NAN_SETTER(SetFillStyle);
|
||||
static NAN_SETTER(SetStrokeStyle);
|
||||
static NAN_SETTER(SetFont);
|
||||
static NAN_SETTER(SetTextBaseline);
|
||||
static NAN_SETTER(SetTextAlign);
|
||||
inline void setContext(cairo_t *ctx) { _context = ctx; }
|
||||
inline cairo_t *context(){ return _context; }
|
||||
inline Canvas *canvas(){ return _canvas; }
|
||||
inline bool hasShadow();
|
||||
void inline setSourceRGBA(rgba_t color);
|
||||
void inline setSourceRGBA(cairo_t *ctx, rgba_t color);
|
||||
void setTextPath(double x, double y);
|
||||
void blur(cairo_surface_t *surface, int radius);
|
||||
void shadow(void (fn)(cairo_t *cr));
|
||||
void shadowStart();
|
||||
void shadowApply();
|
||||
void savePath();
|
||||
void restorePath();
|
||||
void saveState();
|
||||
void restoreState();
|
||||
void inline setFillRule(v8::Local<v8::Value> value);
|
||||
void fill(bool preserve = false);
|
||||
void stroke(bool preserve = false);
|
||||
void save();
|
||||
void restore();
|
||||
void setFontFromState();
|
||||
void resetState();
|
||||
inline PangoLayout *layout(){ return _layout; }
|
||||
|
||||
private:
|
||||
~Context2d();
|
||||
void _resetPersistentHandles();
|
||||
v8::Local<v8::Value> _getFillColor();
|
||||
v8::Local<v8::Value> _getStrokeColor();
|
||||
void _setFillColor(v8::Local<v8::Value> arg);
|
||||
void _setFillPattern(v8::Local<v8::Value> arg);
|
||||
void _setStrokeColor(v8::Local<v8::Value> arg);
|
||||
void _setStrokePattern(v8::Local<v8::Value> arg);
|
||||
Nan::Persistent<v8::Value> _fillStyle;
|
||||
Nan::Persistent<v8::Value> _strokeStyle;
|
||||
Canvas *_canvas;
|
||||
cairo_t *_context;
|
||||
cairo_path_t *_path;
|
||||
PangoLayout *_layout;
|
||||
};
|
||||
@@ -0,0 +1,226 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cairo.h"
|
||||
#include "Canvas.h"
|
||||
#include "color.h"
|
||||
#include "napi.h"
|
||||
#include "uv.h"
|
||||
#include <pango/pangocairo.h>
|
||||
#include <stack>
|
||||
|
||||
/*
|
||||
* State struct.
|
||||
*
|
||||
* Used in conjunction with Save() / Restore() since
|
||||
* cairo's gstate maintains only a single source pattern at a time.
|
||||
*/
|
||||
|
||||
struct canvas_state_t {
|
||||
rgba_t fill = { 0, 0, 0, 1 };
|
||||
rgba_t stroke = { 0, 0, 0, 1 };
|
||||
rgba_t shadow = { 0, 0, 0, 0 };
|
||||
double shadowOffsetX = 0.;
|
||||
double shadowOffsetY = 0.;
|
||||
cairo_pattern_t* fillPattern = nullptr;
|
||||
cairo_pattern_t* strokePattern = nullptr;
|
||||
cairo_pattern_t* fillGradient = nullptr;
|
||||
cairo_pattern_t* strokeGradient = nullptr;
|
||||
PangoFontDescription* fontDescription = nullptr;
|
||||
std::string font = "10px sans-serif";
|
||||
cairo_filter_t patternQuality = CAIRO_FILTER_GOOD;
|
||||
float globalAlpha = 1.f;
|
||||
int shadowBlur = 0;
|
||||
text_align_t textAlignment = TEXT_ALIGNMENT_LEFT; // TODO default is supposed to be START
|
||||
text_baseline_t textBaseline = TEXT_BASELINE_ALPHABETIC;
|
||||
canvas_draw_mode_t textDrawingMode = TEXT_DRAW_PATHS;
|
||||
bool imageSmoothingEnabled = true;
|
||||
|
||||
canvas_state_t() {
|
||||
fontDescription = pango_font_description_from_string("sans");
|
||||
pango_font_description_set_absolute_size(fontDescription, 10 * PANGO_SCALE);
|
||||
}
|
||||
|
||||
canvas_state_t(const canvas_state_t& other) {
|
||||
fill = other.fill;
|
||||
stroke = other.stroke;
|
||||
patternQuality = other.patternQuality;
|
||||
fillPattern = other.fillPattern;
|
||||
strokePattern = other.strokePattern;
|
||||
fillGradient = other.fillGradient;
|
||||
strokeGradient = other.strokeGradient;
|
||||
globalAlpha = other.globalAlpha;
|
||||
textAlignment = other.textAlignment;
|
||||
textBaseline = other.textBaseline;
|
||||
shadow = other.shadow;
|
||||
shadowBlur = other.shadowBlur;
|
||||
shadowOffsetX = other.shadowOffsetX;
|
||||
shadowOffsetY = other.shadowOffsetY;
|
||||
textDrawingMode = other.textDrawingMode;
|
||||
fontDescription = pango_font_description_copy(other.fontDescription);
|
||||
font = other.font;
|
||||
imageSmoothingEnabled = other.imageSmoothingEnabled;
|
||||
}
|
||||
|
||||
~canvas_state_t() {
|
||||
pango_font_description_free(fontDescription);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Equivalent to a PangoRectangle but holds floats instead of ints
|
||||
* (software pixels are stored here instead of pango units)
|
||||
*
|
||||
* Should be compatible with PANGO_ASCENT, PANGO_LBEARING, etc.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
float x;
|
||||
float y;
|
||||
float width;
|
||||
float height;
|
||||
} float_rectangle;
|
||||
|
||||
class Context2d : public Napi::ObjectWrap<Context2d> {
|
||||
public:
|
||||
std::stack<canvas_state_t> states;
|
||||
canvas_state_t *state;
|
||||
Context2d(Canvas *canvas);
|
||||
static Napi::FunctionReference _DOMMatrix;
|
||||
static Napi::FunctionReference _parseFont;
|
||||
static Napi::FunctionReference constructor;
|
||||
static void Initialize(Napi::Env& env, Napi::Object& target);
|
||||
static Napi::Value New(const Napi::CallbackInfo& info);
|
||||
static Napi::Value SaveExternalModules(const Napi::CallbackInfo& info);
|
||||
static Napi::Value DrawImage(const Napi::CallbackInfo& info);
|
||||
static Napi::Value PutImageData(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Save(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Restore(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Rotate(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Translate(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Scale(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Transform(const Napi::CallbackInfo& info);
|
||||
static Napi::Value GetTransform(const Napi::CallbackInfo& info);
|
||||
static Napi::Value ResetTransform(const Napi::CallbackInfo& info);
|
||||
static Napi::Value SetTransform(const Napi::CallbackInfo& info);
|
||||
static Napi::Value IsPointInPath(const Napi::CallbackInfo& info);
|
||||
static Napi::Value BeginPath(const Napi::CallbackInfo& info);
|
||||
static Napi::Value ClosePath(const Napi::CallbackInfo& info);
|
||||
static Napi::Value AddPage(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Clip(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Fill(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Stroke(const Napi::CallbackInfo& info);
|
||||
static Napi::Value FillText(const Napi::CallbackInfo& info);
|
||||
static Napi::Value StrokeText(const Napi::CallbackInfo& info);
|
||||
static Napi::Value SetFont(const Napi::CallbackInfo& info);
|
||||
static Napi::Value SetFillColor(const Napi::CallbackInfo& info);
|
||||
static Napi::Value SetStrokeColor(const Napi::CallbackInfo& info);
|
||||
static Napi::Value SetStrokePattern(const Napi::CallbackInfo& info);
|
||||
static Napi::Value SetTextAlignment(const Napi::CallbackInfo& info);
|
||||
static Napi::Value SetLineDash(const Napi::CallbackInfo& info);
|
||||
static Napi::Value GetLineDash(const Napi::CallbackInfo& info);
|
||||
static Napi::Value MeasureText(const Napi::CallbackInfo& info);
|
||||
static Napi::Value BezierCurveTo(const Napi::CallbackInfo& info);
|
||||
static Napi::Value QuadraticCurveTo(const Napi::CallbackInfo& info);
|
||||
static Napi::Value LineTo(const Napi::CallbackInfo& info);
|
||||
static Napi::Value MoveTo(const Napi::CallbackInfo& info);
|
||||
static Napi::Value FillRect(const Napi::CallbackInfo& info);
|
||||
static Napi::Value StrokeRect(const Napi::CallbackInfo& info);
|
||||
static Napi::Value ClearRect(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Rect(const Napi::CallbackInfo& info);
|
||||
static Napi::Value RoundRect(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Arc(const Napi::CallbackInfo& info);
|
||||
static Napi::Value ArcTo(const Napi::CallbackInfo& info);
|
||||
static Napi::Value Ellipse(const Napi::CallbackInfo& info);
|
||||
static Napi::Value GetImageData(const Napi::CallbackInfo& info);
|
||||
static Napi::Value CreateImageData(const Napi::CallbackInfo& info);
|
||||
static Napi::Value GetStrokeColor(const Napi::CallbackInfo& info);
|
||||
static Napi::Value CreatePattern(const Napi::CallbackInfo& info);
|
||||
static Napi::Value CreateLinearGradient(const Napi::CallbackInfo& info);
|
||||
static Napi::Value CreateRadialGradient(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetFormat(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetPatternQuality(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetImageSmoothingEnabled(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetGlobalCompositeOperation(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetGlobalAlpha(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetShadowColor(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetMiterLimit(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetLineCap(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetLineJoin(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetLineWidth(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetLineDashOffset(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetShadowOffsetX(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetShadowOffsetY(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetShadowBlur(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetAntiAlias(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetTextDrawingMode(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetQuality(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetCurrentTransform(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetFillStyle(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetStrokeStyle(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetFont(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetTextBaseline(const Napi::CallbackInfo& info);
|
||||
Napi::Value GetTextAlign(const Napi::CallbackInfo& info);
|
||||
void SetPatternQuality(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetImageSmoothingEnabled(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetGlobalCompositeOperation(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetGlobalAlpha(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetShadowColor(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetMiterLimit(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetLineCap(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetLineJoin(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetLineWidth(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetLineDashOffset(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetShadowOffsetX(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetShadowOffsetY(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetShadowBlur(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetAntiAlias(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetTextDrawingMode(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetQuality(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetCurrentTransform(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetFillStyle(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetStrokeStyle(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetFont(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetTextBaseline(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
void SetTextAlign(const Napi::CallbackInfo& info, const Napi::Value& value);
|
||||
inline void setContext(cairo_t *ctx) { _context = ctx; }
|
||||
inline cairo_t *context(){ return _context; }
|
||||
inline Canvas *canvas(){ return _canvas; }
|
||||
inline bool hasShadow();
|
||||
void inline setSourceRGBA(rgba_t color);
|
||||
void inline setSourceRGBA(cairo_t *ctx, rgba_t color);
|
||||
void setTextPath(double x, double y);
|
||||
void blur(cairo_surface_t *surface, int radius);
|
||||
void shadow(void (fn)(cairo_t *cr));
|
||||
void shadowStart();
|
||||
void shadowApply();
|
||||
void savePath();
|
||||
void restorePath();
|
||||
void saveState();
|
||||
void restoreState();
|
||||
void inline setFillRule(Napi::Value value);
|
||||
void fill(bool preserve = false);
|
||||
void stroke(bool preserve = false);
|
||||
void save();
|
||||
void restore();
|
||||
void setFontFromState();
|
||||
void resetState();
|
||||
inline PangoLayout *layout(){ return _layout; }
|
||||
|
||||
private:
|
||||
~Context2d();
|
||||
void _resetPersistentHandles();
|
||||
Napi::Value _getFillColor();
|
||||
Napi::Value _getStrokeColor();
|
||||
void _setFillColor(Napi::Value arg);
|
||||
void _setFillPattern(Napi::Value arg);
|
||||
void _setStrokeColor(Napi::Value arg);
|
||||
void _setStrokePattern(Napi::Value arg);
|
||||
Napi::Persistent<v8::Value> _fillStyle;
|
||||
Napi::Persistent<v8::Value> _strokeStyle;
|
||||
Canvas *_canvas;
|
||||
cairo_t *_context;
|
||||
cairo_path_t *_path;
|
||||
PangoLayout *_layout;
|
||||
};
|
||||
1434
npm-packages/mac-v2.4.x/canvas/src/Image.cc
Normal file
1434
npm-packages/mac-v2.4.x/canvas/src/Image.cc
Normal file
File diff suppressed because it is too large
Load Diff
127
npm-packages/mac-v2.4.x/canvas/src/Image.h
Normal file
127
npm-packages/mac-v2.4.x/canvas/src/Image.h
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cairo.h>
|
||||
#include "CanvasError.h"
|
||||
#include <functional>
|
||||
#include <nan.h>
|
||||
#include <stdint.h> // node < 7 uses libstdc++ on macOS which lacks complete c++11
|
||||
#include <v8.h>
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
#include <jpeglib.h>
|
||||
#include <jerror.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GIF
|
||||
#include <gif_lib.h>
|
||||
|
||||
#if GIFLIB_MAJOR > 5 || GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1
|
||||
#define GIF_CLOSE_FILE(gif) DGifCloseFile(gif, NULL)
|
||||
#else
|
||||
#define GIF_CLOSE_FILE(gif) DGifCloseFile(gif)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RSVG
|
||||
#include <librsvg/rsvg.h>
|
||||
// librsvg <= 2.36.1, identified by undefined macro, needs an extra include
|
||||
#ifndef LIBRSVG_CHECK_VERSION
|
||||
#include <librsvg/rsvg-cairo.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
using JPEGDecodeL = std::function<uint32_t (uint8_t* const src)>;
|
||||
|
||||
class Image: public Nan::ObjectWrap {
|
||||
public:
|
||||
char *filename;
|
||||
int width, height;
|
||||
int naturalWidth, naturalHeight;
|
||||
static Nan::Persistent<v8::FunctionTemplate> constructor;
|
||||
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
|
||||
static NAN_METHOD(New);
|
||||
static NAN_GETTER(GetComplete);
|
||||
static NAN_GETTER(GetWidth);
|
||||
static NAN_GETTER(GetHeight);
|
||||
static NAN_GETTER(GetNaturalWidth);
|
||||
static NAN_GETTER(GetNaturalHeight);
|
||||
static NAN_GETTER(GetDataMode);
|
||||
static NAN_SETTER(SetDataMode);
|
||||
static NAN_SETTER(SetWidth);
|
||||
static NAN_SETTER(SetHeight);
|
||||
static NAN_METHOD(GetSource);
|
||||
static NAN_METHOD(SetSource);
|
||||
inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); }
|
||||
inline int stride(){ return cairo_image_surface_get_stride(_surface); }
|
||||
static int isPNG(uint8_t *data);
|
||||
static int isJPEG(uint8_t *data);
|
||||
static int isGIF(uint8_t *data);
|
||||
static int isSVG(uint8_t *data, unsigned len);
|
||||
static int isBMP(uint8_t *data, unsigned len);
|
||||
static cairo_status_t readPNG(void *closure, unsigned char *data, unsigned len);
|
||||
inline int isComplete(){ return COMPLETE == state; }
|
||||
cairo_surface_t *surface();
|
||||
cairo_status_t loadSurface();
|
||||
cairo_status_t loadFromBuffer(uint8_t *buf, unsigned len);
|
||||
cairo_status_t loadPNGFromBuffer(uint8_t *buf);
|
||||
cairo_status_t loadPNG();
|
||||
void clearData();
|
||||
#ifdef HAVE_RSVG
|
||||
cairo_status_t loadSVGFromBuffer(uint8_t *buf, unsigned len);
|
||||
cairo_status_t loadSVG(FILE *stream);
|
||||
cairo_status_t renderSVGToSurface();
|
||||
#endif
|
||||
#ifdef HAVE_GIF
|
||||
cairo_status_t loadGIFFromBuffer(uint8_t *buf, unsigned len);
|
||||
cairo_status_t loadGIF(FILE *stream);
|
||||
#endif
|
||||
#ifdef HAVE_JPEG
|
||||
cairo_status_t loadJPEGFromBuffer(uint8_t *buf, unsigned len);
|
||||
cairo_status_t loadJPEG(FILE *stream);
|
||||
void jpegToARGB(jpeg_decompress_struct* args, uint8_t* data, uint8_t* src, JPEGDecodeL decode);
|
||||
cairo_status_t decodeJPEGIntoSurface(jpeg_decompress_struct *info);
|
||||
cairo_status_t decodeJPEGBufferIntoMimeSurface(uint8_t *buf, unsigned len);
|
||||
cairo_status_t assignDataAsMime(uint8_t *data, int len, const char *mime_type);
|
||||
#endif
|
||||
cairo_status_t loadBMPFromBuffer(uint8_t *buf, unsigned len);
|
||||
cairo_status_t loadBMP(FILE *stream);
|
||||
CanvasError errorInfo;
|
||||
void loaded();
|
||||
cairo_status_t load();
|
||||
Image();
|
||||
|
||||
enum {
|
||||
DEFAULT
|
||||
, LOADING
|
||||
, COMPLETE
|
||||
} state;
|
||||
|
||||
enum data_mode_t {
|
||||
DATA_IMAGE = 1
|
||||
, DATA_MIME = 2
|
||||
} data_mode;
|
||||
|
||||
typedef enum {
|
||||
UNKNOWN
|
||||
, GIF
|
||||
, JPEG
|
||||
, PNG
|
||||
, SVG
|
||||
} type;
|
||||
|
||||
static type extension(const char *filename);
|
||||
|
||||
private:
|
||||
cairo_surface_t *_surface;
|
||||
uint8_t *_data = nullptr;
|
||||
int _data_len;
|
||||
#ifdef HAVE_RSVG
|
||||
RsvgHandle *_rsvg;
|
||||
bool _is_svg;
|
||||
int _svg_last_width;
|
||||
int _svg_last_height;
|
||||
#endif
|
||||
~Image();
|
||||
};
|
||||
146
npm-packages/mac-v2.4.x/canvas/src/ImageData.cc
Normal file
146
npm-packages/mac-v2.4.x/canvas/src/ImageData.cc
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#include "ImageData.h"
|
||||
|
||||
using namespace v8;
|
||||
|
||||
Nan::Persistent<FunctionTemplate> ImageData::constructor;
|
||||
|
||||
/*
|
||||
* Initialize ImageData.
|
||||
*/
|
||||
|
||||
void
|
||||
ImageData::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
// Constructor
|
||||
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(ImageData::New);
|
||||
constructor.Reset(ctor);
|
||||
ctor->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
ctor->SetClassName(Nan::New("ImageData").ToLocalChecked());
|
||||
|
||||
// Prototype
|
||||
Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
|
||||
Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth);
|
||||
Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight);
|
||||
Local<Context> ctx = Nan::GetCurrentContext();
|
||||
Nan::Set(target, Nan::New("ImageData").ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked());
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a new ImageData object.
|
||||
*/
|
||||
|
||||
NAN_METHOD(ImageData::New) {
|
||||
if (!info.IsConstructCall()) {
|
||||
return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
|
||||
}
|
||||
|
||||
Local<TypedArray> dataArray;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
int length;
|
||||
|
||||
if (info[0]->IsUint32() && info[1]->IsUint32()) {
|
||||
width = Nan::To<uint32_t>(info[0]).FromMaybe(0);
|
||||
if (width == 0) {
|
||||
Nan::ThrowRangeError("The source width is zero.");
|
||||
return;
|
||||
}
|
||||
height = Nan::To<uint32_t>(info[1]).FromMaybe(0);
|
||||
if (height == 0) {
|
||||
Nan::ThrowRangeError("The source height is zero.");
|
||||
return;
|
||||
}
|
||||
length = width * height * 4; // ImageData(w, h) constructor assumes 4 BPP; documented.
|
||||
|
||||
dataArray = Uint8ClampedArray::New(ArrayBuffer::New(Isolate::GetCurrent(), length), 0, length);
|
||||
|
||||
} else if (info[0]->IsUint8ClampedArray() && info[1]->IsUint32()) {
|
||||
dataArray = info[0].As<Uint8ClampedArray>();
|
||||
|
||||
length = dataArray->Length();
|
||||
if (length == 0) {
|
||||
Nan::ThrowRangeError("The input data has a zero byte length.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't assert that the ImageData length is a multiple of four because some
|
||||
// data formats are not 4 BPP.
|
||||
|
||||
width = Nan::To<uint32_t>(info[1]).FromMaybe(0);
|
||||
if (width == 0) {
|
||||
Nan::ThrowRangeError("The source width is zero.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't assert that the byte length is a multiple of 4 * width, ditto.
|
||||
|
||||
if (info[2]->IsUint32()) { // Explicit height given
|
||||
height = Nan::To<uint32_t>(info[2]).FromMaybe(0);
|
||||
} else { // Calculate height assuming 4 BPP
|
||||
int size = length / 4;
|
||||
height = size / width;
|
||||
}
|
||||
|
||||
} else if (info[0]->IsUint16Array() && info[1]->IsUint32()) { // Intended for RGB16_565 format
|
||||
dataArray = info[0].As<Uint16Array>();
|
||||
|
||||
length = dataArray->Length();
|
||||
if (length == 0) {
|
||||
Nan::ThrowRangeError("The input data has a zero byte length.");
|
||||
return;
|
||||
}
|
||||
|
||||
width = Nan::To<uint32_t>(info[1]).FromMaybe(0);
|
||||
if (width == 0) {
|
||||
Nan::ThrowRangeError("The source width is zero.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (info[2]->IsUint32()) { // Explicit height given
|
||||
height = Nan::To<uint32_t>(info[2]).FromMaybe(0);
|
||||
} else { // Calculate height assuming 2 BPP
|
||||
int size = length / 2;
|
||||
height = size / width;
|
||||
}
|
||||
|
||||
} else {
|
||||
Nan::ThrowTypeError("Expected (Uint8ClampedArray, width[, height]), (Uint16Array, width[, height]) or (width, height)");
|
||||
return;
|
||||
}
|
||||
|
||||
Nan::TypedArrayContents<uint8_t> dataPtr(dataArray);
|
||||
|
||||
ImageData *imageData = new ImageData(reinterpret_cast<uint8_t*>(*dataPtr), width, height);
|
||||
imageData->Wrap(info.This());
|
||||
Nan::Set(info.This(), Nan::New("data").ToLocalChecked(), dataArray).Check();
|
||||
info.GetReturnValue().Set(info.This());
|
||||
}
|
||||
|
||||
/*
|
||||
* Get width.
|
||||
*/
|
||||
|
||||
NAN_GETTER(ImageData::GetWidth) {
|
||||
if (!ImageData::constructor.Get(info.GetIsolate())->HasInstance(info.This())) {
|
||||
Nan::ThrowTypeError("Method ImageData.GetWidth called on incompatible receiver");
|
||||
return;
|
||||
}
|
||||
ImageData *imageData = Nan::ObjectWrap::Unwrap<ImageData>(info.This());
|
||||
info.GetReturnValue().Set(Nan::New<Number>(imageData->width()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get height.
|
||||
*/
|
||||
|
||||
NAN_GETTER(ImageData::GetHeight) {
|
||||
if (!ImageData::constructor.Get(info.GetIsolate())->HasInstance(info.This())) {
|
||||
Nan::ThrowTypeError("Method ImageData.GetHeight called on incompatible receiver");
|
||||
return;
|
||||
}
|
||||
ImageData *imageData = Nan::ObjectWrap::Unwrap<ImageData>(info.This());
|
||||
info.GetReturnValue().Set(Nan::New<Number>(imageData->height()));
|
||||
}
|
||||
27
npm-packages/mac-v2.4.x/canvas/src/ImageData.h
Normal file
27
npm-packages/mac-v2.4.x/canvas/src/ImageData.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nan.h>
|
||||
#include <stdint.h> // node < 7 uses libstdc++ on macOS which lacks complete c++11
|
||||
#include <v8.h>
|
||||
|
||||
class ImageData: public Nan::ObjectWrap {
|
||||
public:
|
||||
static Nan::Persistent<v8::FunctionTemplate> constructor;
|
||||
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
|
||||
static NAN_METHOD(New);
|
||||
static NAN_GETTER(GetWidth);
|
||||
static NAN_GETTER(GetHeight);
|
||||
|
||||
inline int width() { return _width; }
|
||||
inline int height() { return _height; }
|
||||
inline uint8_t *data() { return _data; }
|
||||
ImageData(uint8_t *data, int width, int height) : _width(width), _height(height), _data(data) {}
|
||||
|
||||
private:
|
||||
int _width;
|
||||
int _height;
|
||||
uint8_t *_data;
|
||||
|
||||
};
|
||||
8
npm-packages/mac-v2.4.x/canvas/src/InstanceData.h
Normal file
8
npm-packages/mac-v2.4.x/canvas/src/InstanceData.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <napi.h>
|
||||
|
||||
struct InstanceData {
|
||||
Napi::FunctionReference ImageBackendCtor;
|
||||
Napi::FunctionReference PdfBackendCtor;
|
||||
Napi::FunctionReference SvgBackendCtor;
|
||||
Napi::FunctionReference CanvasCtor;
|
||||
};
|
||||
167
npm-packages/mac-v2.4.x/canvas/src/JPEGStream.h
Normal file
167
npm-packages/mac-v2.4.x/canvas/src/JPEGStream.h
Normal file
@@ -0,0 +1,167 @@
|
||||
#pragma once
|
||||
|
||||
#include "closure.h"
|
||||
#include <jpeglib.h>
|
||||
#include <jerror.h>
|
||||
|
||||
/*
|
||||
* Expanded data destination object for closure output,
|
||||
* inspired by IJG's jdatadst.c
|
||||
*/
|
||||
|
||||
struct closure_destination_mgr {
|
||||
jpeg_destination_mgr pub;
|
||||
JpegClosure* closure;
|
||||
JOCTET *buffer;
|
||||
int bufsize;
|
||||
};
|
||||
|
||||
void
|
||||
init_closure_destination(j_compress_ptr cinfo){
|
||||
// we really don't have to do anything here
|
||||
}
|
||||
|
||||
boolean
|
||||
empty_closure_output_buffer(j_compress_ptr cinfo){
|
||||
Nan::HandleScope scope;
|
||||
Nan::AsyncResource async("canvas:empty_closure_output_buffer");
|
||||
closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest;
|
||||
|
||||
v8::Local<v8::Object> buf = Nan::NewBuffer((char *)dest->buffer, dest->bufsize).ToLocalChecked();
|
||||
|
||||
// emit "data"
|
||||
v8::Local<v8::Value> argv[2] = {
|
||||
Nan::Null()
|
||||
, buf
|
||||
};
|
||||
dest->closure->cb.Call(sizeof argv / sizeof *argv, argv, &async);
|
||||
|
||||
dest->buffer = (JOCTET *)malloc(dest->bufsize);
|
||||
cinfo->dest->next_output_byte = dest->buffer;
|
||||
cinfo->dest->free_in_buffer = dest->bufsize;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
term_closure_destination(j_compress_ptr cinfo){
|
||||
Nan::HandleScope scope;
|
||||
Nan::AsyncResource async("canvas:term_closure_destination");
|
||||
closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest;
|
||||
|
||||
/* emit remaining data */
|
||||
v8::Local<v8::Object> buf = Nan::NewBuffer((char *)dest->buffer, dest->bufsize - dest->pub.free_in_buffer).ToLocalChecked();
|
||||
|
||||
v8::Local<v8::Value> data_argv[2] = {
|
||||
Nan::Null()
|
||||
, buf
|
||||
};
|
||||
dest->closure->cb.Call(sizeof data_argv / sizeof *data_argv, data_argv, &async);
|
||||
|
||||
// emit "end"
|
||||
v8::Local<v8::Value> end_argv[2] = {
|
||||
Nan::Null()
|
||||
, Nan::Null()
|
||||
};
|
||||
dest->closure->cb.Call(sizeof end_argv / sizeof *end_argv, end_argv, &async);
|
||||
}
|
||||
|
||||
void
|
||||
jpeg_closure_dest(j_compress_ptr cinfo, JpegClosure* closure, int bufsize){
|
||||
closure_destination_mgr * dest;
|
||||
|
||||
/* The destination object is made permanent so that multiple JPEG images
|
||||
* can be written to the same buffer without re-executing jpeg_mem_dest.
|
||||
*/
|
||||
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
|
||||
cinfo->dest = (struct jpeg_destination_mgr *)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||
sizeof(closure_destination_mgr));
|
||||
}
|
||||
|
||||
dest = (closure_destination_mgr *) cinfo->dest;
|
||||
|
||||
cinfo->dest->init_destination = &init_closure_destination;
|
||||
cinfo->dest->empty_output_buffer = &empty_closure_output_buffer;
|
||||
cinfo->dest->term_destination = &term_closure_destination;
|
||||
|
||||
dest->closure = closure;
|
||||
dest->bufsize = bufsize;
|
||||
dest->buffer = (JOCTET *)malloc(bufsize);
|
||||
|
||||
cinfo->dest->next_output_byte = dest->buffer;
|
||||
cinfo->dest->free_in_buffer = dest->bufsize;
|
||||
}
|
||||
|
||||
void encode_jpeg(jpeg_compress_struct cinfo, cairo_surface_t *surface, int quality, bool progressive, int chromaHSampFactor, int chromaVSampFactor) {
|
||||
int w = cairo_image_surface_get_width(surface);
|
||||
int h = cairo_image_surface_get_height(surface);
|
||||
|
||||
cinfo.in_color_space = JCS_RGB;
|
||||
cinfo.input_components = 3;
|
||||
cinfo.image_width = w;
|
||||
cinfo.image_height = h;
|
||||
jpeg_set_defaults(&cinfo);
|
||||
if (progressive)
|
||||
jpeg_simple_progression(&cinfo);
|
||||
jpeg_set_quality(&cinfo, quality, (quality < 25) ? 0 : 1);
|
||||
cinfo.comp_info[0].h_samp_factor = chromaHSampFactor;
|
||||
cinfo.comp_info[0].v_samp_factor = chromaVSampFactor;
|
||||
|
||||
JSAMPROW slr;
|
||||
jpeg_start_compress(&cinfo, TRUE);
|
||||
unsigned char *dst;
|
||||
unsigned int *src = (unsigned int *)cairo_image_surface_get_data(surface);
|
||||
int sl = 0;
|
||||
dst = (unsigned char *)malloc(w * 3);
|
||||
while (sl < h) {
|
||||
unsigned char *dp = dst;
|
||||
int x = 0;
|
||||
while (x < w) {
|
||||
dp[0] = (*src >> 16) & 255;
|
||||
dp[1] = (*src >> 8) & 255;
|
||||
dp[2] = *src & 255;
|
||||
src++;
|
||||
dp += 3;
|
||||
x++;
|
||||
}
|
||||
slr = dst;
|
||||
jpeg_write_scanlines(&cinfo, &slr, 1);
|
||||
sl++;
|
||||
}
|
||||
free(dst);
|
||||
jpeg_finish_compress(&cinfo);
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
}
|
||||
|
||||
void
|
||||
write_to_jpeg_stream(cairo_surface_t *surface, int bufsize, JpegClosure* closure) {
|
||||
jpeg_compress_struct cinfo;
|
||||
jpeg_error_mgr jerr;
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_compress(&cinfo);
|
||||
jpeg_closure_dest(&cinfo, closure, bufsize);
|
||||
encode_jpeg(
|
||||
cinfo,
|
||||
surface,
|
||||
closure->quality,
|
||||
closure->progressive,
|
||||
closure->chromaSubsampling,
|
||||
closure->chromaSubsampling);
|
||||
}
|
||||
|
||||
void
|
||||
write_to_jpeg_buffer(cairo_surface_t* surface, JpegClosure* closure) {
|
||||
jpeg_compress_struct cinfo;
|
||||
jpeg_error_mgr jerr;
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_compress(&cinfo);
|
||||
cinfo.client_data = closure;
|
||||
cinfo.dest = closure->jpeg_dest_mgr;
|
||||
encode_jpeg(
|
||||
cinfo,
|
||||
surface,
|
||||
closure->quality,
|
||||
closure->progressive,
|
||||
closure->chromaSubsampling,
|
||||
closure->chromaSubsampling);
|
||||
}
|
||||
292
npm-packages/mac-v2.4.x/canvas/src/PNG.h
Normal file
292
npm-packages/mac-v2.4.x/canvas/src/PNG.h
Normal file
@@ -0,0 +1,292 @@
|
||||
#pragma once
|
||||
|
||||
#include <cairo.h>
|
||||
#include "closure.h"
|
||||
#include <cmath> // round
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <png.h>
|
||||
#include <pngconf.h>
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
|
||||
#define likely(expr) (__builtin_expect (!!(expr), 1))
|
||||
#define unlikely(expr) (__builtin_expect (!!(expr), 0))
|
||||
#else
|
||||
#define likely(expr) (expr)
|
||||
#define unlikely(expr) (expr)
|
||||
#endif
|
||||
|
||||
static void canvas_png_flush(png_structp png_ptr) {
|
||||
/* Do nothing; fflush() is said to be just a waste of energy. */
|
||||
(void) png_ptr; /* Stifle compiler warning */
|
||||
}
|
||||
|
||||
/* Converts native endian xRGB => RGBx bytes */
|
||||
static void canvas_convert_data_to_bytes(png_structp png, png_row_infop row_info, png_bytep data) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < row_info->rowbytes; i += 4) {
|
||||
uint8_t *b = &data[i];
|
||||
uint32_t pixel;
|
||||
|
||||
memcpy(&pixel, b, sizeof (uint32_t));
|
||||
|
||||
b[0] = (pixel & 0xff0000) >> 16;
|
||||
b[1] = (pixel & 0x00ff00) >> 8;
|
||||
b[2] = (pixel & 0x0000ff) >> 0;
|
||||
b[3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */
|
||||
static void canvas_unpremultiply_data(png_structp png, png_row_infop row_info, png_bytep data) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < row_info->rowbytes; i += 4) {
|
||||
uint8_t *b = &data[i];
|
||||
uint32_t pixel;
|
||||
uint8_t alpha;
|
||||
|
||||
memcpy(&pixel, b, sizeof (uint32_t));
|
||||
alpha = (pixel & 0xff000000) >> 24;
|
||||
if (alpha == 0) {
|
||||
b[0] = b[1] = b[2] = b[3] = 0;
|
||||
} else {
|
||||
b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
|
||||
b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
|
||||
b[2] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
|
||||
b[3] = alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Converts RGB16_565 format data to RGBA32 */
|
||||
static void canvas_convert_565_to_888(png_structp png, png_row_infop row_info, png_bytep data) {
|
||||
// Loop in reverse to unpack in-place.
|
||||
for (ptrdiff_t col = row_info->width - 1; col >= 0; col--) {
|
||||
uint8_t* src = &data[col * sizeof(uint16_t)];
|
||||
uint8_t* dst = &data[col * 3];
|
||||
uint16_t pixel;
|
||||
|
||||
memcpy(&pixel, src, sizeof(uint16_t));
|
||||
|
||||
// Convert and rescale to the full 0-255 range
|
||||
// See http://stackoverflow.com/a/29326693
|
||||
const uint8_t red5 = (pixel & 0xF800) >> 11;
|
||||
const uint8_t green6 = (pixel & 0x7E0) >> 5;
|
||||
const uint8_t blue5 = (pixel & 0x001F);
|
||||
|
||||
dst[0] = ((red5 * 255 + 15) / 31);
|
||||
dst[1] = ((green6 * 255 + 31) / 63);
|
||||
dst[2] = ((blue5 * 255 + 15) / 31);
|
||||
}
|
||||
}
|
||||
|
||||
struct canvas_png_write_closure_t {
|
||||
cairo_write_func_t write_func;
|
||||
PngClosure* closure;
|
||||
};
|
||||
|
||||
#ifdef PNG_SETJMP_SUPPORTED
|
||||
bool setjmp_wrapper(png_structp png) {
|
||||
return setjmp(png_jmpbuf(png));
|
||||
}
|
||||
#endif
|
||||
|
||||
static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr write_func, canvas_png_write_closure_t *closure) {
|
||||
unsigned int i;
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
uint8_t *data;
|
||||
png_structp png;
|
||||
png_infop info;
|
||||
png_bytep *volatile rows = NULL;
|
||||
png_color_16 white;
|
||||
int png_color_type;
|
||||
int bpc;
|
||||
unsigned int width = cairo_image_surface_get_width(surface);
|
||||
unsigned int height = cairo_image_surface_get_height(surface);
|
||||
|
||||
data = cairo_image_surface_get_data(surface);
|
||||
if (data == NULL) {
|
||||
status = CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
|
||||
return status;
|
||||
}
|
||||
cairo_surface_flush(surface);
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
status = CAIRO_STATUS_WRITE_ERROR;
|
||||
return status;
|
||||
}
|
||||
|
||||
rows = (png_bytep *) malloc(height * sizeof (png_byte*));
|
||||
if (unlikely(rows == NULL)) {
|
||||
status = CAIRO_STATUS_NO_MEMORY;
|
||||
return status;
|
||||
}
|
||||
|
||||
int stride = cairo_image_surface_get_stride(surface);
|
||||
for (i = 0; i < height; i++) {
|
||||
rows[i] = (png_byte *) data + i * stride;
|
||||
}
|
||||
|
||||
#ifdef PNG_USER_MEM_SUPPORTED
|
||||
png = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
#else
|
||||
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
#endif
|
||||
|
||||
if (unlikely(png == NULL)) {
|
||||
status = CAIRO_STATUS_NO_MEMORY;
|
||||
free(rows);
|
||||
return status;
|
||||
}
|
||||
|
||||
info = png_create_info_struct (png);
|
||||
if (unlikely(info == NULL)) {
|
||||
status = CAIRO_STATUS_NO_MEMORY;
|
||||
png_destroy_write_struct(&png, &info);
|
||||
free(rows);
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
#ifdef PNG_SETJMP_SUPPORTED
|
||||
if (setjmp_wrapper(png)) {
|
||||
png_destroy_write_struct(&png, &info);
|
||||
free(rows);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
png_set_write_fn(png, closure, write_func, canvas_png_flush);
|
||||
png_set_compression_level(png, closure->closure->compressionLevel);
|
||||
png_set_filter(png, 0, closure->closure->filters);
|
||||
if (closure->closure->resolution != 0) {
|
||||
uint32_t res = static_cast<uint32_t>(round(static_cast<double>(closure->closure->resolution) * 39.3701));
|
||||
png_set_pHYs(png, info, res, res, PNG_RESOLUTION_METER);
|
||||
}
|
||||
|
||||
cairo_format_t format = cairo_image_surface_get_format(surface);
|
||||
|
||||
switch (format) {
|
||||
case CAIRO_FORMAT_ARGB32:
|
||||
bpc = 8;
|
||||
png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
|
||||
break;
|
||||
#ifdef CAIRO_FORMAT_RGB30
|
||||
case CAIRO_FORMAT_RGB30:
|
||||
bpc = 10;
|
||||
png_color_type = PNG_COLOR_TYPE_RGB;
|
||||
break;
|
||||
#endif
|
||||
case CAIRO_FORMAT_RGB24:
|
||||
bpc = 8;
|
||||
png_color_type = PNG_COLOR_TYPE_RGB;
|
||||
break;
|
||||
case CAIRO_FORMAT_A8:
|
||||
bpc = 8;
|
||||
png_color_type = PNG_COLOR_TYPE_GRAY;
|
||||
break;
|
||||
case CAIRO_FORMAT_A1:
|
||||
bpc = 1;
|
||||
png_color_type = PNG_COLOR_TYPE_GRAY;
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
png_set_packswap(png);
|
||||
#endif
|
||||
break;
|
||||
case CAIRO_FORMAT_RGB16_565:
|
||||
bpc = 8; // 565 gets upconverted to 888
|
||||
png_color_type = PNG_COLOR_TYPE_RGB;
|
||||
break;
|
||||
case CAIRO_FORMAT_INVALID:
|
||||
default:
|
||||
status = CAIRO_STATUS_INVALID_FORMAT;
|
||||
png_destroy_write_struct(&png, &info);
|
||||
free(rows);
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((format == CAIRO_FORMAT_A8 || format == CAIRO_FORMAT_A1) &&
|
||||
closure->closure->palette != NULL) {
|
||||
png_color_type = PNG_COLOR_TYPE_PALETTE;
|
||||
}
|
||||
|
||||
png_set_IHDR(png, info, width, height, bpc, png_color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
if (png_color_type == PNG_COLOR_TYPE_PALETTE) {
|
||||
size_t nColors = closure->closure->nPaletteColors;
|
||||
uint8_t* colors = closure->closure->palette;
|
||||
uint8_t backgroundIndex = closure->closure->backgroundIndex;
|
||||
png_colorp pngPalette = (png_colorp)png_malloc(png, nColors * sizeof(png_colorp));
|
||||
png_bytep transparency = (png_bytep)png_malloc(png, nColors * sizeof(png_bytep));
|
||||
for (i = 0; i < nColors; i++) {
|
||||
pngPalette[i].red = colors[4 * i];
|
||||
pngPalette[i].green = colors[4 * i + 1];
|
||||
pngPalette[i].blue = colors[4 * i + 2];
|
||||
transparency[i] = colors[4 * i + 3];
|
||||
}
|
||||
png_set_PLTE(png, info, pngPalette, nColors);
|
||||
png_set_tRNS(png, info, transparency, nColors, NULL);
|
||||
png_set_packing(png); // pack pixels
|
||||
// have libpng free palette and trans:
|
||||
png_data_freer(png, info, PNG_DESTROY_WILL_FREE_DATA, PNG_FREE_PLTE | PNG_FREE_TRNS);
|
||||
png_color_16 bkg;
|
||||
bkg.index = backgroundIndex;
|
||||
png_set_bKGD(png, info, &bkg);
|
||||
}
|
||||
|
||||
if (png_color_type != PNG_COLOR_TYPE_PALETTE) {
|
||||
white.gray = (1 << bpc) - 1;
|
||||
white.red = white.blue = white.green = white.gray;
|
||||
png_set_bKGD(png, info, &white);
|
||||
}
|
||||
|
||||
/* We have to call png_write_info() before setting up the write
|
||||
* transformation, since it stores data internally in 'png'
|
||||
* that is needed for the write transformation functions to work.
|
||||
*/
|
||||
png_write_info(png, info);
|
||||
if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
|
||||
png_set_write_user_transform_fn(png, canvas_unpremultiply_data);
|
||||
} else if (format == CAIRO_FORMAT_RGB16_565) {
|
||||
png_set_write_user_transform_fn(png, canvas_convert_565_to_888);
|
||||
} else if (png_color_type == PNG_COLOR_TYPE_RGB) {
|
||||
png_set_write_user_transform_fn(png, canvas_convert_data_to_bytes);
|
||||
png_set_filler(png, 0, PNG_FILLER_AFTER);
|
||||
}
|
||||
|
||||
png_write_image(png, rows);
|
||||
png_write_end(png, info);
|
||||
|
||||
png_destroy_write_struct(&png, &info);
|
||||
free(rows);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void canvas_stream_write_func(png_structp png, png_bytep data, png_size_t size) {
|
||||
cairo_status_t status;
|
||||
struct canvas_png_write_closure_t *png_closure;
|
||||
|
||||
png_closure = (struct canvas_png_write_closure_t *) png_get_io_ptr(png);
|
||||
status = png_closure->write_func(png_closure->closure, data, size);
|
||||
if (unlikely(status)) {
|
||||
cairo_status_t *error = (cairo_status_t *) png_get_error_ptr(png);
|
||||
if (*error == CAIRO_STATUS_SUCCESS) {
|
||||
*error = status;
|
||||
}
|
||||
png_error(png, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static cairo_status_t canvas_write_to_png_stream(cairo_surface_t *surface, cairo_write_func_t write_func, PngClosure* closure) {
|
||||
struct canvas_png_write_closure_t png_closure;
|
||||
|
||||
if (cairo_surface_status(surface)) {
|
||||
return cairo_surface_status(surface);
|
||||
}
|
||||
|
||||
png_closure.write_func = write_func;
|
||||
png_closure.closure = closure;
|
||||
|
||||
return canvas_write_png(surface, canvas_stream_write_func, &png_closure);
|
||||
}
|
||||
11
npm-packages/mac-v2.4.x/canvas/src/Point.h
Normal file
11
npm-packages/mac-v2.4.x/canvas/src/Point.h
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
#pragma once
|
||||
|
||||
template <typename T>
|
||||
class Point {
|
||||
public:
|
||||
T x, y;
|
||||
Point(T x=0, T y=0): x(x), y(y) {}
|
||||
Point(const Point&) = default;
|
||||
Point& operator=(const Point&) = default;
|
||||
};
|
||||
9
npm-packages/mac-v2.4.x/canvas/src/Util.h
Normal file
9
npm-packages/mac-v2.4.x/canvas/src/Util.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <cctype>
|
||||
|
||||
inline bool streq_casein(std::string& str1, std::string& str2) {
|
||||
return str1.size() == str2.size() && std::equal(str1.begin(), str1.end(), str2.begin(), [](char& c1, char& c2) {
|
||||
return c1 == c2 || std::toupper(c1) == std::toupper(c2);
|
||||
});
|
||||
}
|
||||
112
npm-packages/mac-v2.4.x/canvas/src/backend/Backend.cc
Normal file
112
npm-packages/mac-v2.4.x/canvas/src/backend/Backend.cc
Normal file
@@ -0,0 +1,112 @@
|
||||
#include "Backend.h"
|
||||
#include <string>
|
||||
|
||||
Backend::Backend(std::string name, int width, int height)
|
||||
: name(name)
|
||||
, width(width)
|
||||
, height(height)
|
||||
{}
|
||||
|
||||
Backend::~Backend()
|
||||
{
|
||||
this->destroySurface();
|
||||
}
|
||||
|
||||
void Backend::init(const Nan::FunctionCallbackInfo<v8::Value> &info) {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
if (info[0]->IsNumber()) width = Nan::To<uint32_t>(info[0]).FromMaybe(0);
|
||||
if (info[1]->IsNumber()) height = Nan::To<uint32_t>(info[1]).FromMaybe(0);
|
||||
|
||||
Backend *backend = construct(width, height);
|
||||
|
||||
backend->Wrap(info.This());
|
||||
info.GetReturnValue().Set(info.This());
|
||||
}
|
||||
|
||||
void Backend::setCanvas(Canvas* _canvas)
|
||||
{
|
||||
this->canvas = _canvas;
|
||||
}
|
||||
|
||||
|
||||
cairo_surface_t* Backend::recreateSurface()
|
||||
{
|
||||
this->destroySurface();
|
||||
|
||||
return this->createSurface();
|
||||
}
|
||||
|
||||
DLL_PUBLIC cairo_surface_t* Backend::getSurface() {
|
||||
if (!surface) createSurface();
|
||||
return surface;
|
||||
}
|
||||
|
||||
void Backend::destroySurface()
|
||||
{
|
||||
if(this->surface)
|
||||
{
|
||||
cairo_surface_destroy(this->surface);
|
||||
this->surface = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string Backend::getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
int Backend::getWidth()
|
||||
{
|
||||
return this->width;
|
||||
}
|
||||
void Backend::setWidth(int width_)
|
||||
{
|
||||
this->width = width_;
|
||||
this->recreateSurface();
|
||||
}
|
||||
|
||||
int Backend::getHeight()
|
||||
{
|
||||
return this->height;
|
||||
}
|
||||
void Backend::setHeight(int height_)
|
||||
{
|
||||
this->height = height_;
|
||||
this->recreateSurface();
|
||||
}
|
||||
|
||||
bool Backend::isSurfaceValid(){
|
||||
bool hadSurface = surface != NULL;
|
||||
bool isValid = true;
|
||||
|
||||
cairo_status_t status = cairo_surface_status(getSurface());
|
||||
|
||||
if (status != CAIRO_STATUS_SUCCESS) {
|
||||
error = cairo_status_to_string(status);
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (!hadSurface)
|
||||
destroySurface();
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
|
||||
BackendOperationNotAvailable::BackendOperationNotAvailable(Backend* backend,
|
||||
std::string operation_name)
|
||||
: backend(backend)
|
||||
, operation_name(operation_name)
|
||||
{
|
||||
msg = "operation " + operation_name +
|
||||
" not supported by backend " + backend->getName();
|
||||
};
|
||||
|
||||
BackendOperationNotAvailable::~BackendOperationNotAvailable() throw() {};
|
||||
|
||||
const char* BackendOperationNotAvailable::what() const throw()
|
||||
{
|
||||
return msg.c_str();
|
||||
};
|
||||
69
npm-packages/mac-v2.4.x/canvas/src/backend/Backend.h
Normal file
69
npm-packages/mac-v2.4.x/canvas/src/backend/Backend.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include <cairo.h>
|
||||
#include "../dll_visibility.h"
|
||||
#include <exception>
|
||||
#include <nan.h>
|
||||
#include <string>
|
||||
#include <v8.h>
|
||||
|
||||
class Canvas;
|
||||
|
||||
class Backend : public Nan::ObjectWrap
|
||||
{
|
||||
private:
|
||||
const std::string name;
|
||||
const char* error = NULL;
|
||||
|
||||
protected:
|
||||
int width;
|
||||
int height;
|
||||
cairo_surface_t* surface = nullptr;
|
||||
Canvas* canvas = nullptr;
|
||||
|
||||
Backend(std::string name, int width, int height);
|
||||
static void init(const Nan::FunctionCallbackInfo<v8::Value> &info);
|
||||
static Backend *construct(int width, int height){ return nullptr; }
|
||||
|
||||
public:
|
||||
virtual ~Backend();
|
||||
|
||||
void setCanvas(Canvas* canvas);
|
||||
|
||||
virtual cairo_surface_t* createSurface() = 0;
|
||||
virtual cairo_surface_t* recreateSurface();
|
||||
|
||||
DLL_PUBLIC cairo_surface_t* getSurface();
|
||||
virtual void destroySurface();
|
||||
|
||||
DLL_PUBLIC std::string getName();
|
||||
|
||||
DLL_PUBLIC int getWidth();
|
||||
virtual void setWidth(int width);
|
||||
|
||||
DLL_PUBLIC int getHeight();
|
||||
virtual void setHeight(int height);
|
||||
|
||||
// Overridden by ImageBackend. SVG and PDF thus always return INVALID.
|
||||
virtual cairo_format_t getFormat() {
|
||||
return CAIRO_FORMAT_INVALID;
|
||||
}
|
||||
|
||||
bool isSurfaceValid();
|
||||
inline const char* getError(){ return error; }
|
||||
};
|
||||
|
||||
|
||||
class BackendOperationNotAvailable: public std::exception
|
||||
{
|
||||
private:
|
||||
Backend* backend;
|
||||
std::string operation_name;
|
||||
std::string msg;
|
||||
|
||||
public:
|
||||
BackendOperationNotAvailable(Backend* backend, std::string operation_name);
|
||||
~BackendOperationNotAvailable() throw();
|
||||
|
||||
const char* what() const throw();
|
||||
};
|
||||
74
npm-packages/mac-v2.4.x/canvas/src/backend/ImageBackend.cc
Normal file
74
npm-packages/mac-v2.4.x/canvas/src/backend/ImageBackend.cc
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "ImageBackend.h"
|
||||
|
||||
using namespace v8;
|
||||
|
||||
ImageBackend::ImageBackend(int width, int height)
|
||||
: Backend("image", width, height)
|
||||
{}
|
||||
|
||||
Backend *ImageBackend::construct(int width, int height){
|
||||
return new ImageBackend(width, height);
|
||||
}
|
||||
|
||||
// This returns an approximate value only, suitable for Nan::AdjustExternalMemory.
|
||||
// The formats that don't map to intrinsic types (RGB30, A1) round up.
|
||||
int32_t ImageBackend::approxBytesPerPixel() {
|
||||
switch (format) {
|
||||
case CAIRO_FORMAT_ARGB32:
|
||||
case CAIRO_FORMAT_RGB24:
|
||||
return 4;
|
||||
#ifdef CAIRO_FORMAT_RGB30
|
||||
case CAIRO_FORMAT_RGB30:
|
||||
return 3;
|
||||
#endif
|
||||
case CAIRO_FORMAT_RGB16_565:
|
||||
return 2;
|
||||
case CAIRO_FORMAT_A8:
|
||||
case CAIRO_FORMAT_A1:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
cairo_surface_t* ImageBackend::createSurface() {
|
||||
assert(!surface);
|
||||
surface = cairo_image_surface_create(format, width, height);
|
||||
assert(surface);
|
||||
Nan::AdjustExternalMemory(approxBytesPerPixel() * width * height);
|
||||
return surface;
|
||||
}
|
||||
|
||||
void ImageBackend::destroySurface() {
|
||||
if (surface) {
|
||||
cairo_surface_destroy(surface);
|
||||
surface = nullptr;
|
||||
Nan::AdjustExternalMemory(-approxBytesPerPixel() * width * height);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_format_t ImageBackend::getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
void ImageBackend::setFormat(cairo_format_t _format) {
|
||||
this->format = _format;
|
||||
}
|
||||
|
||||
Nan::Persistent<FunctionTemplate> ImageBackend::constructor;
|
||||
|
||||
void ImageBackend::Initialize(Local<Object> target) {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(ImageBackend::New);
|
||||
ImageBackend::constructor.Reset(ctor);
|
||||
ctor->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
ctor->SetClassName(Nan::New<String>("ImageBackend").ToLocalChecked());
|
||||
Nan::Set(target,
|
||||
Nan::New<String>("ImageBackend").ToLocalChecked(),
|
||||
Nan::GetFunction(ctor).ToLocalChecked()).Check();
|
||||
}
|
||||
|
||||
NAN_METHOD(ImageBackend::New) {
|
||||
init(info);
|
||||
}
|
||||
26
npm-packages/mac-v2.4.x/canvas/src/backend/ImageBackend.h
Normal file
26
npm-packages/mac-v2.4.x/canvas/src/backend/ImageBackend.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "Backend.h"
|
||||
#include <v8.h>
|
||||
|
||||
class ImageBackend : public Backend
|
||||
{
|
||||
private:
|
||||
cairo_surface_t* createSurface();
|
||||
void destroySurface();
|
||||
cairo_format_t format = DEFAULT_FORMAT;
|
||||
|
||||
public:
|
||||
ImageBackend(int width, int height);
|
||||
static Backend *construct(int width, int height);
|
||||
|
||||
cairo_format_t getFormat();
|
||||
void setFormat(cairo_format_t format);
|
||||
|
||||
int32_t approxBytesPerPixel();
|
||||
|
||||
static Nan::Persistent<v8::FunctionTemplate> constructor;
|
||||
static void Initialize(v8::Local<v8::Object> target);
|
||||
static NAN_METHOD(New);
|
||||
const static cairo_format_t DEFAULT_FORMAT = CAIRO_FORMAT_ARGB32;
|
||||
};
|
||||
53
npm-packages/mac-v2.4.x/canvas/src/backend/PdfBackend.cc
Normal file
53
npm-packages/mac-v2.4.x/canvas/src/backend/PdfBackend.cc
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "PdfBackend.h"
|
||||
|
||||
#include <cairo-pdf.h>
|
||||
#include "../Canvas.h"
|
||||
#include "../closure.h"
|
||||
|
||||
using namespace v8;
|
||||
|
||||
PdfBackend::PdfBackend(int width, int height)
|
||||
: Backend("pdf", width, height) {
|
||||
createSurface();
|
||||
}
|
||||
|
||||
PdfBackend::~PdfBackend() {
|
||||
cairo_surface_finish(surface);
|
||||
if (_closure) delete _closure;
|
||||
destroySurface();
|
||||
}
|
||||
|
||||
Backend *PdfBackend::construct(int width, int height){
|
||||
return new PdfBackend(width, height);
|
||||
}
|
||||
|
||||
cairo_surface_t* PdfBackend::createSurface() {
|
||||
if (!_closure) _closure = new PdfSvgClosure(canvas);
|
||||
surface = cairo_pdf_surface_create_for_stream(PdfSvgClosure::writeVec, _closure, width, height);
|
||||
return surface;
|
||||
}
|
||||
|
||||
cairo_surface_t* PdfBackend::recreateSurface() {
|
||||
cairo_pdf_surface_set_size(surface, width, height);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
|
||||
Nan::Persistent<FunctionTemplate> PdfBackend::constructor;
|
||||
|
||||
void PdfBackend::Initialize(Local<Object> target) {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(PdfBackend::New);
|
||||
PdfBackend::constructor.Reset(ctor);
|
||||
ctor->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
ctor->SetClassName(Nan::New<String>("PdfBackend").ToLocalChecked());
|
||||
Nan::Set(target,
|
||||
Nan::New<String>("PdfBackend").ToLocalChecked(),
|
||||
Nan::GetFunction(ctor).ToLocalChecked()).Check();
|
||||
}
|
||||
|
||||
NAN_METHOD(PdfBackend::New) {
|
||||
init(info);
|
||||
}
|
||||
24
npm-packages/mac-v2.4.x/canvas/src/backend/PdfBackend.h
Normal file
24
npm-packages/mac-v2.4.x/canvas/src/backend/PdfBackend.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "Backend.h"
|
||||
#include "../closure.h"
|
||||
#include <v8.h>
|
||||
|
||||
class PdfBackend : public Backend
|
||||
{
|
||||
private:
|
||||
cairo_surface_t* createSurface();
|
||||
cairo_surface_t* recreateSurface();
|
||||
|
||||
public:
|
||||
PdfSvgClosure* _closure = NULL;
|
||||
inline PdfSvgClosure* closure() { return _closure; }
|
||||
|
||||
PdfBackend(int width, int height);
|
||||
~PdfBackend();
|
||||
static Backend *construct(int width, int height);
|
||||
|
||||
static Nan::Persistent<v8::FunctionTemplate> constructor;
|
||||
static void Initialize(v8::Local<v8::Object> target);
|
||||
static NAN_METHOD(New);
|
||||
};
|
||||
61
npm-packages/mac-v2.4.x/canvas/src/backend/SvgBackend.cc
Normal file
61
npm-packages/mac-v2.4.x/canvas/src/backend/SvgBackend.cc
Normal file
@@ -0,0 +1,61 @@
|
||||
#include "SvgBackend.h"
|
||||
|
||||
#include <cairo-svg.h>
|
||||
#include "../Canvas.h"
|
||||
#include "../closure.h"
|
||||
#include <cassert>
|
||||
|
||||
using namespace v8;
|
||||
|
||||
SvgBackend::SvgBackend(int width, int height)
|
||||
: Backend("svg", width, height) {
|
||||
createSurface();
|
||||
}
|
||||
|
||||
SvgBackend::~SvgBackend() {
|
||||
cairo_surface_finish(surface);
|
||||
if (_closure) {
|
||||
delete _closure;
|
||||
_closure = nullptr;
|
||||
}
|
||||
destroySurface();
|
||||
}
|
||||
|
||||
Backend *SvgBackend::construct(int width, int height){
|
||||
return new SvgBackend(width, height);
|
||||
}
|
||||
|
||||
cairo_surface_t* SvgBackend::createSurface() {
|
||||
assert(!_closure);
|
||||
_closure = new PdfSvgClosure(canvas);
|
||||
surface = cairo_svg_surface_create_for_stream(PdfSvgClosure::writeVec, _closure, width, height);
|
||||
return surface;
|
||||
}
|
||||
|
||||
cairo_surface_t* SvgBackend::recreateSurface() {
|
||||
cairo_surface_finish(surface);
|
||||
delete _closure;
|
||||
_closure = nullptr;
|
||||
cairo_surface_destroy(surface);
|
||||
|
||||
return createSurface();
|
||||
}
|
||||
|
||||
|
||||
Nan::Persistent<FunctionTemplate> SvgBackend::constructor;
|
||||
|
||||
void SvgBackend::Initialize(Local<Object> target) {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(SvgBackend::New);
|
||||
SvgBackend::constructor.Reset(ctor);
|
||||
ctor->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
ctor->SetClassName(Nan::New<String>("SvgBackend").ToLocalChecked());
|
||||
Nan::Set(target,
|
||||
Nan::New<String>("SvgBackend").ToLocalChecked(),
|
||||
Nan::GetFunction(ctor).ToLocalChecked()).Check();
|
||||
}
|
||||
|
||||
NAN_METHOD(SvgBackend::New) {
|
||||
init(info);
|
||||
}
|
||||
24
npm-packages/mac-v2.4.x/canvas/src/backend/SvgBackend.h
Normal file
24
npm-packages/mac-v2.4.x/canvas/src/backend/SvgBackend.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "Backend.h"
|
||||
#include "../closure.h"
|
||||
#include <v8.h>
|
||||
|
||||
class SvgBackend : public Backend
|
||||
{
|
||||
private:
|
||||
cairo_surface_t* createSurface();
|
||||
cairo_surface_t* recreateSurface();
|
||||
|
||||
public:
|
||||
PdfSvgClosure* _closure = NULL;
|
||||
inline PdfSvgClosure* closure() { return _closure; }
|
||||
|
||||
SvgBackend(int width, int height);
|
||||
~SvgBackend();
|
||||
static Backend *construct(int width, int height);
|
||||
|
||||
static Nan::Persistent<v8::FunctionTemplate> constructor;
|
||||
static void Initialize(v8::Local<v8::Object> target);
|
||||
static NAN_METHOD(New);
|
||||
};
|
||||
457
npm-packages/mac-v2.4.x/canvas/src/bmp/BMPParser.cc
Normal file
457
npm-packages/mac-v2.4.x/canvas/src/bmp/BMPParser.cc
Normal file
@@ -0,0 +1,457 @@
|
||||
#include "BMPParser.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace std;
|
||||
using namespace BMPParser;
|
||||
|
||||
#define MAX_IMG_SIZE 10000
|
||||
|
||||
#define E(cond, msg) if(cond) return setErr(msg)
|
||||
#define EU(cond, msg) if(cond) return setErrUnsupported(msg)
|
||||
#define EX(cond, msg) if(cond) return setErrUnknown(msg)
|
||||
|
||||
#define I1() get<char>()
|
||||
#define U1() get<uint8_t>()
|
||||
#define I2() get<int16_t>()
|
||||
#define U2() get<uint16_t>()
|
||||
#define I4() get<int32_t>()
|
||||
#define U4() get<uint32_t>()
|
||||
|
||||
#define I1UC() get<char, false>()
|
||||
#define U1UC() get<uint8_t, false>()
|
||||
#define I2UC() get<int16_t, false>()
|
||||
#define U2UC() get<uint16_t, false>()
|
||||
#define I4UC() get<int32_t, false>()
|
||||
#define U4UC() get<uint32_t, false>()
|
||||
|
||||
#define CHECK_OVERRUN(ptr, size, type) \
|
||||
if((ptr) + (size) - data > len){ \
|
||||
setErr("unexpected end of file"); \
|
||||
return type(); \
|
||||
}
|
||||
|
||||
Parser::~Parser(){
|
||||
data = nullptr;
|
||||
ptr = nullptr;
|
||||
|
||||
if(imgd){
|
||||
delete[] imgd;
|
||||
imgd = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::parse(uint8_t *buf, int bufSize, uint8_t *format){
|
||||
assert(status == Status::EMPTY);
|
||||
|
||||
data = ptr = buf;
|
||||
len = bufSize;
|
||||
|
||||
// Start parsing file header
|
||||
setOp("file header");
|
||||
|
||||
// File header signature
|
||||
string fhSig = getStr(2);
|
||||
string temp = "file header signature";
|
||||
EU(fhSig == "BA", temp + " \"BA\"");
|
||||
EU(fhSig == "CI", temp + " \"CI\"");
|
||||
EU(fhSig == "CP", temp + " \"CP\"");
|
||||
EU(fhSig == "IC", temp + " \"IC\"");
|
||||
EU(fhSig == "PT", temp + " \"PT\"");
|
||||
EX(fhSig != "BM", temp); // BM
|
||||
|
||||
// Length of the file should not be larger than `len`
|
||||
E(U4() > static_cast<uint32_t>(len), "inconsistent file size");
|
||||
|
||||
// Skip unused values
|
||||
skip(4);
|
||||
|
||||
// Offset where the pixel array (bitmap data) can be found
|
||||
auto imgdOffset = U4();
|
||||
|
||||
// Start parsing DIB header
|
||||
setOp("DIB header");
|
||||
|
||||
// Prepare some variables in case they are needed
|
||||
uint32_t compr = 0;
|
||||
uint32_t redShift = 0, greenShift = 0, blueShift = 0, alphaShift = 0;
|
||||
uint32_t redMask = 0, greenMask = 0, blueMask = 0, alphaMask = 0;
|
||||
double redMultp = 0, greenMultp = 0, blueMultp = 0, alphaMultp = 0;
|
||||
|
||||
/**
|
||||
* Type of the DIB (device-independent bitmap) header
|
||||
* is determined by its size. Most BMP files use BITMAPINFOHEADER.
|
||||
*/
|
||||
auto dibSize = U4();
|
||||
temp = "DIB header";
|
||||
EU(dibSize == 64, temp + " \"OS22XBITMAPHEADER\"");
|
||||
EU(dibSize == 16, temp + " \"OS22XBITMAPHEADER\"");
|
||||
|
||||
uint32_t infoHeader = dibSize == 40 ? 1 :
|
||||
dibSize == 52 ? 2 :
|
||||
dibSize == 56 ? 3 :
|
||||
dibSize == 108 ? 4 :
|
||||
dibSize == 124 ? 5 : 0;
|
||||
|
||||
// BITMAPCOREHEADER, BITMAP*INFOHEADER, BITMAP*HEADER
|
||||
auto isDibValid = dibSize == 12 || infoHeader;
|
||||
EX(!isDibValid, temp);
|
||||
|
||||
// Image width
|
||||
w = dibSize == 12 ? U2() : I4();
|
||||
E(!w, "image width is 0");
|
||||
E(w < 0, "negative image width");
|
||||
E(w > MAX_IMG_SIZE, "too large image width");
|
||||
|
||||
// Image height (specification allows negative values)
|
||||
h = dibSize == 12 ? U2() : I4();
|
||||
E(!h, "image height is 0");
|
||||
E(h > MAX_IMG_SIZE, "too large image height");
|
||||
|
||||
bool isHeightNegative = h < 0;
|
||||
if(isHeightNegative) h = -h;
|
||||
|
||||
// Number of color planes (must be 1)
|
||||
E(U2() != 1, "number of color planes must be 1");
|
||||
|
||||
// Bits per pixel (color depth)
|
||||
auto bpp = U2();
|
||||
auto isBppValid = bpp == 1 || bpp == 4 || bpp == 8 || bpp == 16 || bpp == 24 || bpp == 32;
|
||||
EU(!isBppValid, "color depth");
|
||||
|
||||
// Calculate image data size and padding
|
||||
uint32_t expectedImgdSize = (((w * bpp + 31) >> 5) << 2) * h;
|
||||
uint32_t rowPadding = (-w * bpp & 31) >> 3;
|
||||
uint32_t imgdSize = 0;
|
||||
|
||||
// Color palette data
|
||||
uint8_t* paletteStart = nullptr;
|
||||
uint32_t palColNum = 0;
|
||||
|
||||
if(infoHeader){
|
||||
// Compression type
|
||||
compr = U4();
|
||||
temp = "compression type";
|
||||
EU(compr == 1, temp + " \"BI_RLE8\"");
|
||||
EU(compr == 2, temp + " \"BI_RLE4\"");
|
||||
EU(compr == 4, temp + " \"BI_JPEG\"");
|
||||
EU(compr == 5, temp + " \"BI_PNG\"");
|
||||
EU(compr == 6, temp + " \"BI_ALPHABITFIELDS\"");
|
||||
EU(compr == 11, temp + " \"BI_CMYK\"");
|
||||
EU(compr == 12, temp + " \"BI_CMYKRLE8\"");
|
||||
EU(compr == 13, temp + " \"BI_CMYKRLE4\"");
|
||||
|
||||
// BI_RGB and BI_BITFIELDS
|
||||
auto isComprValid = compr == 0 || compr == 3;
|
||||
EX(!isComprValid, temp);
|
||||
|
||||
// Ensure that BI_BITFIELDS appears only with 16-bit or 32-bit color
|
||||
E(compr == 3 && !(bpp == 16 || bpp == 32), "compression BI_BITFIELDS can be used only with 16-bit and 32-bit color depth");
|
||||
|
||||
// Size of the image data
|
||||
imgdSize = U4();
|
||||
|
||||
// Horizontal and vertical resolution (ignored)
|
||||
skip(8);
|
||||
|
||||
// Number of colors in the palette or 0 if no palette is present
|
||||
palColNum = U4();
|
||||
EU(palColNum && bpp > 8, "color palette and bit depth combination");
|
||||
if(palColNum) paletteStart = data + dibSize + 14;
|
||||
|
||||
// Number of important colors used or 0 if all colors are important (generally ignored)
|
||||
skip(4);
|
||||
|
||||
if(infoHeader >= 2){
|
||||
// If BI_BITFIELDS are used, calculate masks, otherwise ignore them
|
||||
if(compr == 3){
|
||||
calcMaskShift(redShift, redMask, redMultp);
|
||||
calcMaskShift(greenShift, greenMask, greenMultp);
|
||||
calcMaskShift(blueShift, blueMask, blueMultp);
|
||||
if(infoHeader >= 3) calcMaskShift(alphaShift, alphaMask, alphaMultp);
|
||||
if(status == Status::ERROR) return;
|
||||
}else{
|
||||
skip(16);
|
||||
}
|
||||
|
||||
// Ensure that the color space is LCS_WINDOWS_COLOR_SPACE or sRGB
|
||||
if(infoHeader >= 4 && !palColNum){
|
||||
string colSpace = getStr(4, 1);
|
||||
EU(colSpace != "Win " && colSpace != "sRGB", "color space \"" + colSpace + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skip to the image data (there may be other chunks between, but they are optional)
|
||||
E(ptr - data > imgdOffset, "image data overlaps with another structure");
|
||||
ptr = data + imgdOffset;
|
||||
|
||||
// Start parsing image data
|
||||
setOp("image data");
|
||||
|
||||
if(!imgdSize){
|
||||
// Value 0 is allowed only for BI_RGB compression type
|
||||
E(compr != 0, "missing image data size");
|
||||
imgdSize = expectedImgdSize;
|
||||
}else{
|
||||
E(imgdSize < expectedImgdSize, "invalid image data size");
|
||||
}
|
||||
|
||||
// Ensure that all image data is present
|
||||
E(ptr - data + imgdSize > len, "not enough image data");
|
||||
|
||||
// Direction of reading rows
|
||||
int yStart = h - 1;
|
||||
int yEnd = -1;
|
||||
int dy = isHeightNegative ? 1 : -1;
|
||||
|
||||
// In case of negative height, read rows backward
|
||||
if(isHeightNegative){
|
||||
yStart = 0;
|
||||
yEnd = h;
|
||||
}
|
||||
|
||||
// Allocate output image data array
|
||||
int buffLen = w * h << 2;
|
||||
imgd = new (nothrow) uint8_t[buffLen];
|
||||
E(!imgd, "unable to allocate memory");
|
||||
|
||||
// Prepare color values
|
||||
uint8_t color[4] = {0};
|
||||
uint8_t &red = color[0];
|
||||
uint8_t &green = color[1];
|
||||
uint8_t &blue = color[2];
|
||||
uint8_t &alpha = color[3];
|
||||
|
||||
// Check if pre-multiplied alpha is used
|
||||
bool premul = format ? format[4] : 0;
|
||||
|
||||
// Main loop
|
||||
for(int y = yStart; y != yEnd; y += dy){
|
||||
// Use in-byte offset for bpp < 8
|
||||
uint8_t colOffset = 0;
|
||||
uint8_t cval = 0;
|
||||
uint32_t val = 0;
|
||||
|
||||
for(int x = 0; x != w; x++){
|
||||
// Index in the output image data
|
||||
int i = (x + y * w) << 2;
|
||||
|
||||
switch(compr){
|
||||
case 0: // BI_RGB
|
||||
switch(bpp){
|
||||
case 1:
|
||||
if(colOffset) ptr--;
|
||||
cval = (U1UC() >> (7 - colOffset)) & 1;
|
||||
|
||||
if(palColNum){
|
||||
uint8_t* entry = paletteStart + (cval << 2);
|
||||
blue = get<uint8_t>(entry);
|
||||
green = get<uint8_t>(entry + 1);
|
||||
red = get<uint8_t>(entry + 2);
|
||||
if(status == Status::ERROR) return;
|
||||
}else{
|
||||
red = green = blue = cval ? 255 : 0;
|
||||
}
|
||||
|
||||
alpha = 255;
|
||||
colOffset = (colOffset + 1) & 7;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if(colOffset) ptr--;
|
||||
cval = (U1UC() >> (4 - colOffset)) & 15;
|
||||
|
||||
if(palColNum){
|
||||
uint8_t* entry = paletteStart + (cval << 2);
|
||||
blue = get<uint8_t>(entry);
|
||||
green = get<uint8_t>(entry + 1);
|
||||
red = get<uint8_t>(entry + 2);
|
||||
if(status == Status::ERROR) return;
|
||||
}else{
|
||||
red = green = blue = cval << 4;
|
||||
}
|
||||
|
||||
alpha = 255;
|
||||
colOffset = (colOffset + 4) & 7;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
cval = U1UC();
|
||||
|
||||
if(palColNum){
|
||||
uint8_t* entry = paletteStart + (cval << 2);
|
||||
blue = get<uint8_t>(entry);
|
||||
green = get<uint8_t>(entry + 1);
|
||||
red = get<uint8_t>(entry + 2);
|
||||
if(status == Status::ERROR) return;
|
||||
}else{
|
||||
red = green = blue = cval;
|
||||
}
|
||||
|
||||
alpha = 255;
|
||||
break;
|
||||
|
||||
case 16:
|
||||
// RGB555
|
||||
val = U1UC();
|
||||
val |= U1UC() << 8;
|
||||
red = (val >> 10) << 3;
|
||||
green = (val >> 5) << 3;
|
||||
blue = val << 3;
|
||||
alpha = 255;
|
||||
break;
|
||||
|
||||
case 24:
|
||||
blue = U1UC();
|
||||
green = U1UC();
|
||||
red = U1UC();
|
||||
alpha = 255;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
blue = U1UC();
|
||||
green = U1UC();
|
||||
red = U1UC();
|
||||
|
||||
if(infoHeader >= 3){
|
||||
alpha = U1UC();
|
||||
}else{
|
||||
alpha = 255;
|
||||
skip(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // BI_BITFIELDS
|
||||
uint32_t col = bpp == 16 ? U2UC() : U4UC();
|
||||
red = ((col >> redShift) & redMask) * redMultp + .5;
|
||||
green = ((col >> greenShift) & greenMask) * greenMultp + .5;
|
||||
blue = ((col >> blueShift) & blueMask) * blueMultp + .5;
|
||||
alpha = alphaMask ? ((col >> alphaShift) & alphaMask) * alphaMultp + .5 : 255;
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pixel format:
|
||||
* red,
|
||||
* green,
|
||||
* blue,
|
||||
* alpha,
|
||||
* is alpha pre-multiplied
|
||||
* Default is [0, 1, 2, 3, 0]
|
||||
*/
|
||||
|
||||
if(premul && alpha != 255){
|
||||
double a = alpha / 255.;
|
||||
red = static_cast<uint8_t>(red * a + .5);
|
||||
green = static_cast<uint8_t>(green * a + .5);
|
||||
blue = static_cast<uint8_t>(blue * a + .5);
|
||||
}
|
||||
|
||||
if(format){
|
||||
imgd[i] = color[format[0]];
|
||||
imgd[i + 1] = color[format[1]];
|
||||
imgd[i + 2] = color[format[2]];
|
||||
imgd[i + 3] = color[format[3]];
|
||||
}else{
|
||||
imgd[i] = red;
|
||||
imgd[i + 1] = green;
|
||||
imgd[i + 2] = blue;
|
||||
imgd[i + 3] = alpha;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip unused bytes in the current row
|
||||
skip(rowPadding);
|
||||
}
|
||||
|
||||
if(status == Status::ERROR) return;
|
||||
status = Status::OK;
|
||||
};
|
||||
|
||||
void Parser::clearImgd(){ imgd = nullptr; }
|
||||
int32_t Parser::getWidth() const{ return w; }
|
||||
int32_t Parser::getHeight() const{ return h; }
|
||||
uint8_t *Parser::getImgd() const{ return imgd; }
|
||||
Status Parser::getStatus() const{ return status; }
|
||||
|
||||
string Parser::getErrMsg() const{
|
||||
return "Error while processing " + getOp() + " - " + err;
|
||||
}
|
||||
|
||||
template <typename T, bool check> inline T Parser::get(){
|
||||
if(check)
|
||||
CHECK_OVERRUN(ptr, sizeof(T), T);
|
||||
T val = *(T*)ptr;
|
||||
ptr += sizeof(T);
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T, bool check> inline T Parser::get(uint8_t* pointer){
|
||||
if(check)
|
||||
CHECK_OVERRUN(pointer, sizeof(T), T);
|
||||
T val = *(T*)pointer;
|
||||
return val;
|
||||
}
|
||||
|
||||
string Parser::getStr(int size, bool reverse){
|
||||
CHECK_OVERRUN(ptr, size, string);
|
||||
string val = "";
|
||||
|
||||
while(size--){
|
||||
if(reverse) val = string(1, static_cast<char>(*ptr++)) + val;
|
||||
else val += static_cast<char>(*ptr++);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
inline void Parser::skip(int size){
|
||||
CHECK_OVERRUN(ptr, size, void);
|
||||
ptr += size;
|
||||
}
|
||||
|
||||
void Parser::calcMaskShift(uint32_t& shift, uint32_t& mask, double& multp){
|
||||
mask = U4();
|
||||
shift = 0;
|
||||
|
||||
if(mask == 0) return;
|
||||
|
||||
while(~mask & 1){
|
||||
mask >>= 1;
|
||||
shift++;
|
||||
}
|
||||
|
||||
E(mask & (mask + 1), "invalid color mask");
|
||||
|
||||
multp = 255. / mask;
|
||||
}
|
||||
|
||||
void Parser::setOp(string val){
|
||||
if(status != Status::EMPTY) return;
|
||||
op = val;
|
||||
}
|
||||
|
||||
string Parser::getOp() const{
|
||||
return op;
|
||||
}
|
||||
|
||||
void Parser::setErrUnsupported(string msg){
|
||||
setErr("unsupported " + msg);
|
||||
}
|
||||
|
||||
void Parser::setErrUnknown(string msg){
|
||||
setErr("unknown " + msg);
|
||||
}
|
||||
|
||||
void Parser::setErr(string msg){
|
||||
if(status != Status::EMPTY) return;
|
||||
err = msg;
|
||||
status = Status::ERROR;
|
||||
}
|
||||
|
||||
string Parser::getErr() const{
|
||||
return err;
|
||||
}
|
||||
60
npm-packages/mac-v2.4.x/canvas/src/bmp/BMPParser.h
Normal file
60
npm-packages/mac-v2.4.x/canvas/src/bmp/BMPParser.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef ERROR
|
||||
#define ERROR_ ERROR
|
||||
#undef ERROR
|
||||
#endif
|
||||
|
||||
#include <stdint.h> // node < 7 uses libstdc++ on macOS which lacks complete c++11
|
||||
#include <string>
|
||||
|
||||
namespace BMPParser{
|
||||
enum Status{
|
||||
EMPTY,
|
||||
OK,
|
||||
ERROR,
|
||||
};
|
||||
|
||||
class Parser{
|
||||
public:
|
||||
Parser()=default;
|
||||
~Parser();
|
||||
void parse(uint8_t *buf, int bufSize, uint8_t *format=nullptr);
|
||||
void clearImgd();
|
||||
int32_t getWidth() const;
|
||||
int32_t getHeight() const;
|
||||
uint8_t *getImgd() const;
|
||||
Status getStatus() const;
|
||||
std::string getErrMsg() const;
|
||||
|
||||
private:
|
||||
Status status = Status::EMPTY;
|
||||
uint8_t *data = nullptr;
|
||||
uint8_t *ptr = nullptr;
|
||||
int len = 0;
|
||||
int32_t w = 0;
|
||||
int32_t h = 0;
|
||||
uint8_t *imgd = nullptr;
|
||||
std::string err = "";
|
||||
std::string op = "";
|
||||
|
||||
template <typename T, bool check=true> inline T get();
|
||||
template <typename T, bool check=true> inline T get(uint8_t* pointer);
|
||||
std::string getStr(int len, bool reverse=false);
|
||||
inline void skip(int len);
|
||||
void calcMaskShift(uint32_t& shift, uint32_t& mask, double& multp);
|
||||
|
||||
void setOp(std::string val);
|
||||
std::string getOp() const;
|
||||
|
||||
void setErrUnsupported(std::string msg);
|
||||
void setErrUnknown(std::string msg);
|
||||
void setErr(std::string msg);
|
||||
std::string getErr() const;
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef ERROR_
|
||||
#define ERROR ERROR_
|
||||
#undef ERROR_
|
||||
#endif
|
||||
24
npm-packages/mac-v2.4.x/canvas/src/bmp/LICENSE.md
Normal file
24
npm-packages/mac-v2.4.x/canvas/src/bmp/LICENSE.md
Normal file
@@ -0,0 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org>
|
||||
26
npm-packages/mac-v2.4.x/canvas/src/closure.cc
Normal file
26
npm-packages/mac-v2.4.x/canvas/src/closure.cc
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "closure.h"
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
void JpegClosure::init_destination(j_compress_ptr cinfo) {
|
||||
JpegClosure* closure = (JpegClosure*)cinfo->client_data;
|
||||
closure->vec.resize(PAGE_SIZE);
|
||||
closure->jpeg_dest_mgr->next_output_byte = &closure->vec[0];
|
||||
closure->jpeg_dest_mgr->free_in_buffer = closure->vec.size();
|
||||
}
|
||||
|
||||
boolean JpegClosure::empty_output_buffer(j_compress_ptr cinfo) {
|
||||
JpegClosure* closure = (JpegClosure*)cinfo->client_data;
|
||||
size_t currentSize = closure->vec.size();
|
||||
closure->vec.resize(currentSize * 1.5);
|
||||
closure->jpeg_dest_mgr->next_output_byte = &closure->vec[currentSize];
|
||||
closure->jpeg_dest_mgr->free_in_buffer = closure->vec.size() - currentSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
void JpegClosure::term_destination(j_compress_ptr cinfo) {
|
||||
JpegClosure* closure = (JpegClosure*)cinfo->client_data;
|
||||
size_t finalSize = closure->vec.size() - closure->jpeg_dest_mgr->free_in_buffer;
|
||||
closure->vec.resize(finalSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
81
npm-packages/mac-v2.4.x/canvas/src/closure.h
Normal file
81
npm-packages/mac-v2.4.x/canvas/src/closure.h
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Canvas.h"
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
#include <jpeglib.h>
|
||||
#endif
|
||||
|
||||
#include <nan.h>
|
||||
#include <png.h>
|
||||
#include <stdint.h> // node < 7 uses libstdc++ on macOS which lacks complete c++11
|
||||
#include <vector>
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Image encoding closures.
|
||||
*/
|
||||
|
||||
struct Closure {
|
||||
std::vector<uint8_t> vec;
|
||||
Nan::Callback cb;
|
||||
Canvas* canvas = nullptr;
|
||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||
|
||||
static cairo_status_t writeVec(void *c, const uint8_t *odata, unsigned len) {
|
||||
Closure* closure = static_cast<Closure*>(c);
|
||||
try {
|
||||
closure->vec.insert(closure->vec.end(), odata, odata + len);
|
||||
} catch (const std::bad_alloc &) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
Closure(Canvas* canvas) : canvas(canvas) {};
|
||||
};
|
||||
|
||||
struct PdfSvgClosure : Closure {
|
||||
PdfSvgClosure(Canvas* canvas) : Closure(canvas) {};
|
||||
};
|
||||
|
||||
struct PngClosure : Closure {
|
||||
uint32_t compressionLevel = 6;
|
||||
uint32_t filters = PNG_ALL_FILTERS;
|
||||
uint32_t resolution = 0; // 0 = unspecified
|
||||
// Indexed PNGs:
|
||||
uint32_t nPaletteColors = 0;
|
||||
uint8_t* palette = nullptr;
|
||||
uint8_t backgroundIndex = 0;
|
||||
|
||||
PngClosure(Canvas* canvas) : Closure(canvas) {};
|
||||
};
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
struct JpegClosure : Closure {
|
||||
uint32_t quality = 75;
|
||||
uint32_t chromaSubsampling = 2;
|
||||
bool progressive = false;
|
||||
jpeg_destination_mgr* jpeg_dest_mgr = nullptr;
|
||||
|
||||
static void init_destination(j_compress_ptr cinfo);
|
||||
static boolean empty_output_buffer(j_compress_ptr cinfo);
|
||||
static void term_destination(j_compress_ptr cinfo);
|
||||
|
||||
JpegClosure(Canvas* canvas) : Closure(canvas) {
|
||||
jpeg_dest_mgr = new jpeg_destination_mgr;
|
||||
jpeg_dest_mgr->init_destination = init_destination;
|
||||
jpeg_dest_mgr->empty_output_buffer = empty_output_buffer;
|
||||
jpeg_dest_mgr->term_destination = term_destination;
|
||||
};
|
||||
|
||||
~JpegClosure() {
|
||||
delete jpeg_dest_mgr;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
779
npm-packages/mac-v2.4.x/canvas/src/color.cc
Normal file
779
npm-packages/mac-v2.4.x/canvas/src/color.cc
Normal file
@@ -0,0 +1,779 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#include "color.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
// Compatibility with Visual Studio versions prior to VS2015
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Parse integer value
|
||||
*/
|
||||
|
||||
template <typename parsed_t>
|
||||
static bool
|
||||
parse_integer(const char** pStr, parsed_t *pParsed) {
|
||||
parsed_t& c = *pParsed;
|
||||
const char*& str = *pStr;
|
||||
int8_t sign=1;
|
||||
|
||||
c = 0;
|
||||
if (*str == '-') {
|
||||
sign=-1;
|
||||
++str;
|
||||
}
|
||||
else if (*str == '+')
|
||||
++str;
|
||||
|
||||
if (*str >= '0' && *str <= '9') {
|
||||
do {
|
||||
c *= 10;
|
||||
c += *str++ - '0';
|
||||
} while (*str >= '0' && *str <= '9');
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (sign<0)
|
||||
c=-c;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse CSS <number> value
|
||||
* Adapted from http://crackprogramming.blogspot.co.il/2012/10/implement-atof.html
|
||||
*/
|
||||
|
||||
template <typename parsed_t>
|
||||
static bool
|
||||
parse_css_number(const char** pStr, parsed_t *pParsed) {
|
||||
parsed_t &parsed = *pParsed;
|
||||
const char*& str = *pStr;
|
||||
const char* startStr = str;
|
||||
if (!str || !*str)
|
||||
return false;
|
||||
parsed_t integerPart = 0;
|
||||
parsed_t fractionPart = 0;
|
||||
int divisorForFraction = 1;
|
||||
int sign = 1;
|
||||
int exponent = 0;
|
||||
int digits = 0;
|
||||
bool inFraction = false;
|
||||
|
||||
if (*str == '-') {
|
||||
++str;
|
||||
sign = -1;
|
||||
}
|
||||
else if (*str == '+')
|
||||
++str;
|
||||
while (*str != '\0') {
|
||||
if (*str >= '0' && *str <= '9') {
|
||||
if (digits>=std::numeric_limits<parsed_t>::digits10) {
|
||||
if (!inFraction)
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
++digits;
|
||||
|
||||
if (inFraction) {
|
||||
fractionPart = fractionPart*10 + (*str - '0');
|
||||
divisorForFraction *= 10;
|
||||
}
|
||||
else {
|
||||
integerPart = integerPart*10 + (*str - '0');
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (*str == '.') {
|
||||
if (inFraction)
|
||||
break;
|
||||
else
|
||||
inFraction = true;
|
||||
}
|
||||
else if (*str == 'e') {
|
||||
++str;
|
||||
if (!parse_integer(&str, &exponent))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
++str;
|
||||
}
|
||||
if (str != startStr) {
|
||||
parsed = sign * (integerPart + fractionPart/divisorForFraction);
|
||||
for (;exponent>0;--exponent)
|
||||
parsed *= 10;
|
||||
for (;exponent<0;++exponent)
|
||||
parsed /= 10;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clip value to the range [minValue, maxValue]
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
static T
|
||||
clip(T value, T minValue, T maxValue) {
|
||||
if (value > maxValue)
|
||||
value = maxValue;
|
||||
if (value < minValue)
|
||||
value = minValue;
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrap value to the range [0, limit]
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
static T
|
||||
wrap_float(T value, T limit) {
|
||||
return fmod(fmod(value, limit) + limit, limit);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrap value to the range [0, limit] - currently-unused integer version of wrap_float
|
||||
*/
|
||||
|
||||
// template <typename T>
|
||||
// static T wrap_int(T value, T limit) {
|
||||
// return (value % limit + limit) % limit;
|
||||
// }
|
||||
|
||||
/*
|
||||
* Parse color channel value
|
||||
*/
|
||||
|
||||
static bool
|
||||
parse_rgb_channel(const char** pStr, uint8_t *pChannel) {
|
||||
int channel;
|
||||
if (parse_integer(pStr, &channel)) {
|
||||
*pChannel = clip(channel, 0, 255);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a value in degrees
|
||||
*/
|
||||
|
||||
static bool
|
||||
parse_degrees(const char** pStr, float *pDegrees) {
|
||||
float degrees;
|
||||
if (parse_css_number(pStr, °rees)) {
|
||||
*pDegrees = wrap_float(degrees, 360.0f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse and clip a percentage value. Returns a float in the range [0, 1].
|
||||
*/
|
||||
|
||||
static bool
|
||||
parse_clipped_percentage(const char** pStr, float *pFraction) {
|
||||
float percentage;
|
||||
bool result = parse_css_number(pStr,&percentage);
|
||||
const char*& str = *pStr;
|
||||
if (result) {
|
||||
if (*str == '%') {
|
||||
++str;
|
||||
*pFraction = clip(percentage, 0.0f, 100.0f) / 100.0f;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Macros to help with parsing inside rgba_from_*_string
|
||||
*/
|
||||
|
||||
#define WHITESPACE \
|
||||
while (' ' == *str) ++str;
|
||||
|
||||
#define WHITESPACE_OR_COMMA \
|
||||
while (' ' == *str || ',' == *str) ++str;
|
||||
|
||||
#define CHANNEL(NAME) \
|
||||
if (!parse_rgb_channel(&str, &NAME)) \
|
||||
return 0; \
|
||||
|
||||
#define HUE(NAME) \
|
||||
if (!parse_degrees(&str, &NAME)) \
|
||||
return 0;
|
||||
|
||||
#define SATURATION(NAME) \
|
||||
if (!parse_clipped_percentage(&str, &NAME)) \
|
||||
return 0;
|
||||
|
||||
#define LIGHTNESS(NAME) SATURATION(NAME)
|
||||
|
||||
#define ALPHA(NAME) \
|
||||
if (*str >= '1' && *str <= '9') { \
|
||||
NAME = 1; \
|
||||
} else { \
|
||||
if ('0' == *str) { \
|
||||
NAME = 0; \
|
||||
++str; \
|
||||
} \
|
||||
if ('.' == *str) { \
|
||||
++str; \
|
||||
NAME = 0; \
|
||||
float n = .1f; \
|
||||
while (*str >= '0' && *str <= '9') { \
|
||||
NAME += (*str++ - '0') * n; \
|
||||
n *= .1f; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
do {} while (0) // require trailing semicolon
|
||||
|
||||
/*
|
||||
* Named colors.
|
||||
*/
|
||||
static const std::map<std::string, uint32_t> named_colors = {
|
||||
{ "transparent", 0xFFFFFF00}
|
||||
, { "aliceblue", 0xF0F8FFFF }
|
||||
, { "antiquewhite", 0xFAEBD7FF }
|
||||
, { "aqua", 0x00FFFFFF }
|
||||
, { "aquamarine", 0x7FFFD4FF }
|
||||
, { "azure", 0xF0FFFFFF }
|
||||
, { "beige", 0xF5F5DCFF }
|
||||
, { "bisque", 0xFFE4C4FF }
|
||||
, { "black", 0x000000FF }
|
||||
, { "blanchedalmond", 0xFFEBCDFF }
|
||||
, { "blue", 0x0000FFFF }
|
||||
, { "blueviolet", 0x8A2BE2FF }
|
||||
, { "brown", 0xA52A2AFF }
|
||||
, { "burlywood", 0xDEB887FF }
|
||||
, { "cadetblue", 0x5F9EA0FF }
|
||||
, { "chartreuse", 0x7FFF00FF }
|
||||
, { "chocolate", 0xD2691EFF }
|
||||
, { "coral", 0xFF7F50FF }
|
||||
, { "cornflowerblue", 0x6495EDFF }
|
||||
, { "cornsilk", 0xFFF8DCFF }
|
||||
, { "crimson", 0xDC143CFF }
|
||||
, { "cyan", 0x00FFFFFF }
|
||||
, { "darkblue", 0x00008BFF }
|
||||
, { "darkcyan", 0x008B8BFF }
|
||||
, { "darkgoldenrod", 0xB8860BFF }
|
||||
, { "darkgray", 0xA9A9A9FF }
|
||||
, { "darkgreen", 0x006400FF }
|
||||
, { "darkgrey", 0xA9A9A9FF }
|
||||
, { "darkkhaki", 0xBDB76BFF }
|
||||
, { "darkmagenta", 0x8B008BFF }
|
||||
, { "darkolivegreen", 0x556B2FFF }
|
||||
, { "darkorange", 0xFF8C00FF }
|
||||
, { "darkorchid", 0x9932CCFF }
|
||||
, { "darkred", 0x8B0000FF }
|
||||
, { "darksalmon", 0xE9967AFF }
|
||||
, { "darkseagreen", 0x8FBC8FFF }
|
||||
, { "darkslateblue", 0x483D8BFF }
|
||||
, { "darkslategray", 0x2F4F4FFF }
|
||||
, { "darkslategrey", 0x2F4F4FFF }
|
||||
, { "darkturquoise", 0x00CED1FF }
|
||||
, { "darkviolet", 0x9400D3FF }
|
||||
, { "deeppink", 0xFF1493FF }
|
||||
, { "deepskyblue", 0x00BFFFFF }
|
||||
, { "dimgray", 0x696969FF }
|
||||
, { "dimgrey", 0x696969FF }
|
||||
, { "dodgerblue", 0x1E90FFFF }
|
||||
, { "firebrick", 0xB22222FF }
|
||||
, { "floralwhite", 0xFFFAF0FF }
|
||||
, { "forestgreen", 0x228B22FF }
|
||||
, { "fuchsia", 0xFF00FFFF }
|
||||
, { "gainsboro", 0xDCDCDCFF }
|
||||
, { "ghostwhite", 0xF8F8FFFF }
|
||||
, { "gold", 0xFFD700FF }
|
||||
, { "goldenrod", 0xDAA520FF }
|
||||
, { "gray", 0x808080FF }
|
||||
, { "green", 0x008000FF }
|
||||
, { "greenyellow", 0xADFF2FFF }
|
||||
, { "grey", 0x808080FF }
|
||||
, { "honeydew", 0xF0FFF0FF }
|
||||
, { "hotpink", 0xFF69B4FF }
|
||||
, { "indianred", 0xCD5C5CFF }
|
||||
, { "indigo", 0x4B0082FF }
|
||||
, { "ivory", 0xFFFFF0FF }
|
||||
, { "khaki", 0xF0E68CFF }
|
||||
, { "lavender", 0xE6E6FAFF }
|
||||
, { "lavenderblush", 0xFFF0F5FF }
|
||||
, { "lawngreen", 0x7CFC00FF }
|
||||
, { "lemonchiffon", 0xFFFACDFF }
|
||||
, { "lightblue", 0xADD8E6FF }
|
||||
, { "lightcoral", 0xF08080FF }
|
||||
, { "lightcyan", 0xE0FFFFFF }
|
||||
, { "lightgoldenrodyellow", 0xFAFAD2FF }
|
||||
, { "lightgray", 0xD3D3D3FF }
|
||||
, { "lightgreen", 0x90EE90FF }
|
||||
, { "lightgrey", 0xD3D3D3FF }
|
||||
, { "lightpink", 0xFFB6C1FF }
|
||||
, { "lightsalmon", 0xFFA07AFF }
|
||||
, { "lightseagreen", 0x20B2AAFF }
|
||||
, { "lightskyblue", 0x87CEFAFF }
|
||||
, { "lightslategray", 0x778899FF }
|
||||
, { "lightslategrey", 0x778899FF }
|
||||
, { "lightsteelblue", 0xB0C4DEFF }
|
||||
, { "lightyellow", 0xFFFFE0FF }
|
||||
, { "lime", 0x00FF00FF }
|
||||
, { "limegreen", 0x32CD32FF }
|
||||
, { "linen", 0xFAF0E6FF }
|
||||
, { "magenta", 0xFF00FFFF }
|
||||
, { "maroon", 0x800000FF }
|
||||
, { "mediumaquamarine", 0x66CDAAFF }
|
||||
, { "mediumblue", 0x0000CDFF }
|
||||
, { "mediumorchid", 0xBA55D3FF }
|
||||
, { "mediumpurple", 0x9370DBFF }
|
||||
, { "mediumseagreen", 0x3CB371FF }
|
||||
, { "mediumslateblue", 0x7B68EEFF }
|
||||
, { "mediumspringgreen", 0x00FA9AFF }
|
||||
, { "mediumturquoise", 0x48D1CCFF }
|
||||
, { "mediumvioletred", 0xC71585FF }
|
||||
, { "midnightblue", 0x191970FF }
|
||||
, { "mintcream", 0xF5FFFAFF }
|
||||
, { "mistyrose", 0xFFE4E1FF }
|
||||
, { "moccasin", 0xFFE4B5FF }
|
||||
, { "navajowhite", 0xFFDEADFF }
|
||||
, { "navy", 0x000080FF }
|
||||
, { "oldlace", 0xFDF5E6FF }
|
||||
, { "olive", 0x808000FF }
|
||||
, { "olivedrab", 0x6B8E23FF }
|
||||
, { "orange", 0xFFA500FF }
|
||||
, { "orangered", 0xFF4500FF }
|
||||
, { "orchid", 0xDA70D6FF }
|
||||
, { "palegoldenrod", 0xEEE8AAFF }
|
||||
, { "palegreen", 0x98FB98FF }
|
||||
, { "paleturquoise", 0xAFEEEEFF }
|
||||
, { "palevioletred", 0xDB7093FF }
|
||||
, { "papayawhip", 0xFFEFD5FF }
|
||||
, { "peachpuff", 0xFFDAB9FF }
|
||||
, { "peru", 0xCD853FFF }
|
||||
, { "pink", 0xFFC0CBFF }
|
||||
, { "plum", 0xDDA0DDFF }
|
||||
, { "powderblue", 0xB0E0E6FF }
|
||||
, { "purple", 0x800080FF }
|
||||
, { "rebeccapurple", 0x663399FF } // Source: CSS Color Level 4 draft
|
||||
, { "red", 0xFF0000FF }
|
||||
, { "rosybrown", 0xBC8F8FFF }
|
||||
, { "royalblue", 0x4169E1FF }
|
||||
, { "saddlebrown", 0x8B4513FF }
|
||||
, { "salmon", 0xFA8072FF }
|
||||
, { "sandybrown", 0xF4A460FF }
|
||||
, { "seagreen", 0x2E8B57FF }
|
||||
, { "seashell", 0xFFF5EEFF }
|
||||
, { "sienna", 0xA0522DFF }
|
||||
, { "silver", 0xC0C0C0FF }
|
||||
, { "skyblue", 0x87CEEBFF }
|
||||
, { "slateblue", 0x6A5ACDFF }
|
||||
, { "slategray", 0x708090FF }
|
||||
, { "slategrey", 0x708090FF }
|
||||
, { "snow", 0xFFFAFAFF }
|
||||
, { "springgreen", 0x00FF7FFF }
|
||||
, { "steelblue", 0x4682B4FF }
|
||||
, { "tan", 0xD2B48CFF }
|
||||
, { "teal", 0x008080FF }
|
||||
, { "thistle", 0xD8BFD8FF }
|
||||
, { "tomato", 0xFF6347FF }
|
||||
, { "turquoise", 0x40E0D0FF }
|
||||
, { "violet", 0xEE82EEFF }
|
||||
, { "wheat", 0xF5DEB3FF }
|
||||
, { "white", 0xFFFFFFFF }
|
||||
, { "whitesmoke", 0xF5F5F5FF }
|
||||
, { "yellow", 0xFFFF00FF }
|
||||
, { "yellowgreen", 0x9ACD32FF }
|
||||
};
|
||||
|
||||
/*
|
||||
* Hex digit int val.
|
||||
*/
|
||||
|
||||
static int
|
||||
h(char c) {
|
||||
switch (c) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return c - '0';
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
return (c - 'a') + 10;
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
return (c - 'A') + 10;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return rgba_t from rgba.
|
||||
*/
|
||||
|
||||
rgba_t
|
||||
rgba_create(uint32_t rgba) {
|
||||
rgba_t color;
|
||||
color.r = (double) (rgba >> 24) / 255;
|
||||
color.g = (double) (rgba >> 16 & 0xff) / 255;
|
||||
color.b = (double) (rgba >> 8 & 0xff) / 255;
|
||||
color.a = (double) (rgba & 0xff) / 255;
|
||||
return color;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a string representation of the color.
|
||||
*/
|
||||
|
||||
void
|
||||
rgba_to_string(rgba_t rgba, char *buf, size_t len) {
|
||||
if (1 == rgba.a) {
|
||||
snprintf(buf, len, "#%.2x%.2x%.2x",
|
||||
static_cast<int>(round(rgba.r * 255)),
|
||||
static_cast<int>(round(rgba.g * 255)),
|
||||
static_cast<int>(round(rgba.b * 255)));
|
||||
} else {
|
||||
snprintf(buf, len, "rgba(%d, %d, %d, %.2f)",
|
||||
static_cast<int>(round(rgba.r * 255)),
|
||||
static_cast<int>(round(rgba.g * 255)),
|
||||
static_cast<int>(round(rgba.b * 255)),
|
||||
rgba.a);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return rgba from (r,g,b,a).
|
||||
*/
|
||||
|
||||
static inline int32_t
|
||||
rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
return
|
||||
r << 24
|
||||
| g << 16
|
||||
| b << 8
|
||||
| a;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function used in rgba_from_hsla().
|
||||
* Based on http://dev.w3.org/csswg/css-color-4/#hsl-to-rgb
|
||||
*/
|
||||
|
||||
static float
|
||||
hue_to_rgb(float t1, float t2, float hue) {
|
||||
if (hue < 0)
|
||||
hue += 6;
|
||||
if (hue >= 6)
|
||||
hue -= 6;
|
||||
|
||||
if (hue < 1)
|
||||
return (t2 - t1) * hue + t1;
|
||||
else if (hue < 3)
|
||||
return t2;
|
||||
else if (hue < 4)
|
||||
return (t2 - t1) * (4 - hue) + t1;
|
||||
else
|
||||
return t1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return rgba from (h,s,l,a).
|
||||
* Expects h values in the range [0, 360), and s, l, a in the range [0, 1].
|
||||
* Adapted from http://dev.w3.org/csswg/css-color-4/#hsl-to-rgb
|
||||
*/
|
||||
|
||||
static inline int32_t
|
||||
rgba_from_hsla(float h_deg, float s, float l, float a) {
|
||||
uint8_t r, g, b;
|
||||
float h = (6 * h_deg) / 360.0f, m1, m2;
|
||||
|
||||
if (l<=0.5)
|
||||
m2=l*(s+1);
|
||||
else
|
||||
m2=l+s-l*s;
|
||||
m1 = l*2 - m2;
|
||||
|
||||
// Scale and round the RGB components
|
||||
r = (uint8_t)floor(hue_to_rgb(m1, m2, h + 2) * 255 + 0.5);
|
||||
g = (uint8_t)floor(hue_to_rgb(m1, m2, h ) * 255 + 0.5);
|
||||
b = (uint8_t)floor(hue_to_rgb(m1, m2, h - 2) * 255 + 0.5);
|
||||
|
||||
return rgba_from_rgba(r, g, b, (uint8_t) (a * 255));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return rgba from (h,s,l).
|
||||
* Expects h values in the range [0, 360), and s, l in the range [0, 1].
|
||||
*/
|
||||
|
||||
static inline int32_t
|
||||
rgba_from_hsl(float h_deg, float s, float l) {
|
||||
return rgba_from_hsla(h_deg, s, l, 1.0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return rgba from (r,g,b).
|
||||
*/
|
||||
|
||||
static int32_t
|
||||
rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) {
|
||||
return rgba_from_rgba(r, g, b, 255);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return rgba from #RRGGBBAA
|
||||
*/
|
||||
|
||||
static int32_t
|
||||
rgba_from_hex8_string(const char *str) {
|
||||
return rgba_from_rgba(
|
||||
(h(str[0]) << 4) + h(str[1]),
|
||||
(h(str[2]) << 4) + h(str[3]),
|
||||
(h(str[4]) << 4) + h(str[5]),
|
||||
(h(str[6]) << 4) + h(str[7])
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return rgb from "#RRGGBB".
|
||||
*/
|
||||
|
||||
static int32_t
|
||||
rgba_from_hex6_string(const char *str) {
|
||||
return rgba_from_rgb(
|
||||
(h(str[0]) << 4) + h(str[1])
|
||||
, (h(str[2]) << 4) + h(str[3])
|
||||
, (h(str[4]) << 4) + h(str[5])
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return rgba from #RGBA
|
||||
*/
|
||||
|
||||
static int32_t
|
||||
rgba_from_hex4_string(const char *str) {
|
||||
return rgba_from_rgba(
|
||||
(h(str[0]) << 4) + h(str[0]),
|
||||
(h(str[1]) << 4) + h(str[1]),
|
||||
(h(str[2]) << 4) + h(str[2]),
|
||||
(h(str[3]) << 4) + h(str[3])
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return rgb from "#RGB"
|
||||
*/
|
||||
|
||||
static int32_t
|
||||
rgba_from_hex3_string(const char *str) {
|
||||
return rgba_from_rgb(
|
||||
(h(str[0]) << 4) + h(str[0])
|
||||
, (h(str[1]) << 4) + h(str[1])
|
||||
, (h(str[2]) << 4) + h(str[2])
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return rgb from "rgb()"
|
||||
*/
|
||||
|
||||
static int32_t
|
||||
rgba_from_rgb_string(const char *str, short *ok) {
|
||||
if (str == strstr(str, "rgb(")) {
|
||||
str += 4;
|
||||
WHITESPACE;
|
||||
uint8_t r = 0, g = 0, b = 0;
|
||||
CHANNEL(r);
|
||||
WHITESPACE_OR_COMMA;
|
||||
CHANNEL(g);
|
||||
WHITESPACE_OR_COMMA;
|
||||
CHANNEL(b);
|
||||
WHITESPACE;
|
||||
return *ok = 1, rgba_from_rgb(r, g, b);
|
||||
}
|
||||
return *ok = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return rgb from "rgba()"
|
||||
*/
|
||||
|
||||
static int32_t
|
||||
rgba_from_rgba_string(const char *str, short *ok) {
|
||||
if (str == strstr(str, "rgba(")) {
|
||||
str += 5;
|
||||
WHITESPACE;
|
||||
uint8_t r = 0, g = 0, b = 0;
|
||||
float a = 1.f;
|
||||
CHANNEL(r);
|
||||
WHITESPACE_OR_COMMA;
|
||||
CHANNEL(g);
|
||||
WHITESPACE_OR_COMMA;
|
||||
CHANNEL(b);
|
||||
WHITESPACE_OR_COMMA;
|
||||
ALPHA(a);
|
||||
WHITESPACE;
|
||||
return *ok = 1, rgba_from_rgba(r, g, b, (int) (a * 255));
|
||||
}
|
||||
return *ok = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return rgb from "hsla()"
|
||||
*/
|
||||
|
||||
static int32_t
|
||||
rgba_from_hsla_string(const char *str, short *ok) {
|
||||
if (str == strstr(str, "hsla(")) {
|
||||
str += 5;
|
||||
WHITESPACE;
|
||||
float h_deg = 0;
|
||||
float s = 0, l = 0;
|
||||
float a = 0;
|
||||
HUE(h_deg);
|
||||
WHITESPACE_OR_COMMA;
|
||||
SATURATION(s);
|
||||
WHITESPACE_OR_COMMA;
|
||||
LIGHTNESS(l);
|
||||
WHITESPACE_OR_COMMA;
|
||||
ALPHA(a);
|
||||
WHITESPACE;
|
||||
return *ok = 1, rgba_from_hsla(h_deg, s, l, a);
|
||||
}
|
||||
return *ok = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return rgb from "hsl()"
|
||||
*/
|
||||
|
||||
static int32_t
|
||||
rgba_from_hsl_string(const char *str, short *ok) {
|
||||
if (str == strstr(str, "hsl(")) {
|
||||
str += 4;
|
||||
WHITESPACE;
|
||||
float h_deg = 0;
|
||||
float s = 0, l = 0;
|
||||
HUE(h_deg);
|
||||
WHITESPACE_OR_COMMA;
|
||||
SATURATION(s);
|
||||
WHITESPACE_OR_COMMA;
|
||||
LIGHTNESS(l);
|
||||
WHITESPACE;
|
||||
return *ok = 1, rgba_from_hsl(h_deg, s, l);
|
||||
}
|
||||
return *ok = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return rgb from:
|
||||
*
|
||||
* - "#RGB"
|
||||
* - "#RGBA"
|
||||
* - "#RRGGBB"
|
||||
* - "#RRGGBBAA"
|
||||
*
|
||||
*/
|
||||
|
||||
static int32_t
|
||||
rgba_from_hex_string(const char *str, short *ok) {
|
||||
size_t len = strlen(str);
|
||||
*ok = 1;
|
||||
switch (len) {
|
||||
case 8: return rgba_from_hex8_string(str);
|
||||
case 6: return rgba_from_hex6_string(str);
|
||||
case 4: return rgba_from_hex4_string(str);
|
||||
case 3: return rgba_from_hex3_string(str);
|
||||
}
|
||||
return *ok = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return named color value.
|
||||
*/
|
||||
|
||||
static int32_t
|
||||
rgba_from_name_string(const char *str, short *ok) {
|
||||
std::string lowered(str);
|
||||
std::transform(lowered.begin(), lowered.end(), lowered.begin(), tolower);
|
||||
auto color = named_colors.find(lowered);
|
||||
if (color != named_colors.end()) {
|
||||
return *ok = 1, color->second;
|
||||
}
|
||||
return *ok = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return rgb from:
|
||||
*
|
||||
* - #RGB
|
||||
* - #RGBA
|
||||
* - #RRGGBB
|
||||
* - #RRGGBBAA
|
||||
* - rgb(r,g,b)
|
||||
* - rgba(r,g,b,a)
|
||||
* - hsl(h,s,l)
|
||||
* - hsla(h,s,l,a)
|
||||
* - name
|
||||
*
|
||||
*/
|
||||
|
||||
int32_t
|
||||
rgba_from_string(const char *str, short *ok) {
|
||||
if ('#' == str[0])
|
||||
return rgba_from_hex_string(++str, ok);
|
||||
if (str == strstr(str, "rgba"))
|
||||
return rgba_from_rgba_string(str, ok);
|
||||
if (str == strstr(str, "rgb"))
|
||||
return rgba_from_rgb_string(str, ok);
|
||||
if (str == strstr(str, "hsla"))
|
||||
return rgba_from_hsla_string(str, ok);
|
||||
if (str == strstr(str, "hsl"))
|
||||
return rgba_from_hsl_string(str, ok);
|
||||
return rgba_from_name_string(str, ok);
|
||||
}
|
||||
|
||||
/*
|
||||
* Inspect the given rgba color.
|
||||
*/
|
||||
|
||||
void
|
||||
rgba_inspect(int32_t rgba) {
|
||||
printf("rgba(%d,%d,%d,%d)\n"
|
||||
, rgba >> 24 & 0xff
|
||||
, rgba >> 16 & 0xff
|
||||
, rgba >> 8 & 0xff
|
||||
, rgba & 0xff
|
||||
);
|
||||
}
|
||||
30
npm-packages/mac-v2.4.x/canvas/src/color.h
Normal file
30
npm-packages/mac-v2.4.x/canvas/src/color.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h> // node < 7 uses libstdc++ on macOS which lacks complete c++11
|
||||
#include <cstdlib>
|
||||
|
||||
/*
|
||||
* RGBA struct.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
double r, g, b, a;
|
||||
} rgba_t;
|
||||
|
||||
/*
|
||||
* Prototypes.
|
||||
*/
|
||||
|
||||
rgba_t
|
||||
rgba_create(uint32_t rgba);
|
||||
|
||||
int32_t
|
||||
rgba_from_string(const char *str, short *ok);
|
||||
|
||||
void
|
||||
rgba_to_string(rgba_t rgba, char *buf, size_t len);
|
||||
|
||||
void
|
||||
rgba_inspect(int32_t rgba);
|
||||
20
npm-packages/mac-v2.4.x/canvas/src/dll_visibility.h
Normal file
20
npm-packages/mac-v2.4.x/canvas/src/dll_visibility.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef DLL_PUBLIC
|
||||
|
||||
#if defined _WIN32
|
||||
#ifdef __GNUC__
|
||||
#define DLL_PUBLIC __attribute__ ((dllexport))
|
||||
#else
|
||||
#define DLL_PUBLIC __declspec(dllexport)
|
||||
#endif
|
||||
#define DLL_LOCAL
|
||||
#else
|
||||
#if __GNUC__ >= 4
|
||||
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
|
||||
#define DLL_LOCAL __attribute__ ((visibility ("hidden")))
|
||||
#else
|
||||
#define DLL_PUBLIC
|
||||
#define DLL_LOCAL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
94
npm-packages/mac-v2.4.x/canvas/src/init.cc
Normal file
94
npm-packages/mac-v2.4.x/canvas/src/init.cc
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
||||
|
||||
#include <cstdio>
|
||||
#include <pango/pango.h>
|
||||
|
||||
#include <cairo.h>
|
||||
#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 10, 0)
|
||||
// CAIRO_FORMAT_RGB16_565: undeprecated in v1.10.0
|
||||
// CAIRO_STATUS_INVALID_SIZE: v1.10.0
|
||||
// CAIRO_FORMAT_INVALID: v1.10.0
|
||||
// Lots of the compositing operators: v1.10.0
|
||||
// JPEG MIME tracking: v1.10.0
|
||||
// Note: CAIRO_FORMAT_RGB30 is v1.12.0 and still optional
|
||||
#error("cairo v1.10.0 or later is required")
|
||||
#endif
|
||||
|
||||
#include "Backends.h"
|
||||
#include "Canvas.h"
|
||||
#include "CanvasGradient.h"
|
||||
#include "CanvasPattern.h"
|
||||
#include "CanvasRenderingContext2d.h"
|
||||
#include "Image.h"
|
||||
#include "ImageData.h"
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
using namespace v8;
|
||||
|
||||
// Compatibility with Visual Studio versions prior to VS2015
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
NAN_MODULE_INIT(init) {
|
||||
Backends::Initialize(target);
|
||||
Canvas::Initialize(target);
|
||||
Image::Initialize(target);
|
||||
ImageData::Initialize(target);
|
||||
Context2d::Initialize(target);
|
||||
Gradient::Initialize(target);
|
||||
Pattern::Initialize(target);
|
||||
|
||||
Nan::Set(target, Nan::New<String>("cairoVersion").ToLocalChecked(), Nan::New<String>(cairo_version_string()).ToLocalChecked()).Check();
|
||||
#ifdef HAVE_JPEG
|
||||
|
||||
#ifndef JPEG_LIB_VERSION_MAJOR
|
||||
#ifdef JPEG_LIB_VERSION
|
||||
#define JPEG_LIB_VERSION_MAJOR (JPEG_LIB_VERSION / 10)
|
||||
#else
|
||||
#define JPEG_LIB_VERSION_MAJOR 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef JPEG_LIB_VERSION_MINOR
|
||||
#ifdef JPEG_LIB_VERSION
|
||||
#define JPEG_LIB_VERSION_MINOR (JPEG_LIB_VERSION % 10)
|
||||
#else
|
||||
#define JPEG_LIB_VERSION_MINOR 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
char jpeg_version[10];
|
||||
static bool minor_gt_0 = JPEG_LIB_VERSION_MINOR > 0;
|
||||
if (minor_gt_0) {
|
||||
snprintf(jpeg_version, 10, "%d%c", JPEG_LIB_VERSION_MAJOR, JPEG_LIB_VERSION_MINOR + 'a' - 1);
|
||||
} else {
|
||||
snprintf(jpeg_version, 10, "%d", JPEG_LIB_VERSION_MAJOR);
|
||||
}
|
||||
Nan::Set(target, Nan::New<String>("jpegVersion").ToLocalChecked(), Nan::New<String>(jpeg_version).ToLocalChecked()).Check();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GIF
|
||||
#ifndef GIF_LIB_VERSION
|
||||
char gif_version[10];
|
||||
snprintf(gif_version, 10, "%d.%d.%d", GIFLIB_MAJOR, GIFLIB_MINOR, GIFLIB_RELEASE);
|
||||
Nan::Set(target, Nan::New<String>("gifVersion").ToLocalChecked(), Nan::New<String>(gif_version).ToLocalChecked()).Check();
|
||||
#else
|
||||
Nan::Set(target, Nan::New<String>("gifVersion").ToLocalChecked(), Nan::New<String>(GIF_LIB_VERSION).ToLocalChecked()).Check();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RSVG
|
||||
Nan::Set(target, Nan::New<String>("rsvgVersion").ToLocalChecked(), Nan::New<String>(LIBRSVG_VERSION).ToLocalChecked()).Check();
|
||||
#endif
|
||||
|
||||
Nan::Set(target, Nan::New<String>("pangoVersion").ToLocalChecked(), Nan::New<String>(PANGO_VERSION_STRING).ToLocalChecked()).Check();
|
||||
|
||||
char freetype_version[10];
|
||||
snprintf(freetype_version, 10, "%d.%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
|
||||
Nan::Set(target, Nan::New<String>("freetypeVersion").ToLocalChecked(), Nan::New<String>(freetype_version).ToLocalChecked()).Check();
|
||||
}
|
||||
|
||||
NODE_MODULE(canvas, init);
|
||||
408
npm-packages/mac-v2.4.x/canvas/src/register_font.cc
Normal file
408
npm-packages/mac-v2.4.x/canvas/src/register_font.cc
Normal file
@@ -0,0 +1,408 @@
|
||||
#include "register_font.h"
|
||||
|
||||
#include <string>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <pango/pango-fontmap.h>
|
||||
#include <pango/pango.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreText/CoreText.h>
|
||||
#elif defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <memory>
|
||||
#else
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#include <pango/pangofc-fontmap.h>
|
||||
#endif
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_TRUETYPE_TABLES_H
|
||||
#include FT_SFNT_NAMES_H
|
||||
#include FT_TRUETYPE_IDS_H
|
||||
#ifndef FT_SFNT_OS2
|
||||
#define FT_SFNT_OS2 ft_sfnt_os2
|
||||
#endif
|
||||
|
||||
// OSX seems to read the strings in MacRoman encoding and ignore Unicode entries.
|
||||
// You can verify this by opening a TTF with both Unicode and Macroman on OSX.
|
||||
// It uses the MacRoman name, while Fontconfig and Windows use Unicode
|
||||
#ifdef __APPLE__
|
||||
#define PREFERRED_PLATFORM_ID TT_PLATFORM_MACINTOSH
|
||||
#define PREFERRED_ENCODING_ID TT_MAC_ID_ROMAN
|
||||
#else
|
||||
#define PREFERRED_PLATFORM_ID TT_PLATFORM_MICROSOFT
|
||||
#define PREFERRED_ENCODING_ID TT_MS_ID_UNICODE_CS
|
||||
#endif
|
||||
|
||||
// With PangoFcFontMaps (the pango font module on Linux) we're able to add a
|
||||
// hook that lets us get perfect matching. Tie the conditions for enabling that
|
||||
// feature to one variable
|
||||
#if !defined(__APPLE__) && !defined(_WIN32) && PANGO_VERSION_CHECK(1, 47, 0)
|
||||
#define PERFECT_MATCHES_ENABLED
|
||||
#endif
|
||||
|
||||
#define IS_PREFERRED_ENC(X) \
|
||||
X.platform_id == PREFERRED_PLATFORM_ID && X.encoding_id == PREFERRED_ENCODING_ID
|
||||
|
||||
#ifdef PERFECT_MATCHES_ENABLED
|
||||
// On Linux-like OSes using FontConfig, the PostScript name ranks higher than
|
||||
// preferred family and family name since we'll use it to get perfect font
|
||||
// matching (see fc_font_map_substitute_hook)
|
||||
#define GET_NAME_RANK(X) \
|
||||
((IS_PREFERRED_ENC(X) ? 1 : 0) << 2) | \
|
||||
((X.name_id == TT_NAME_ID_PS_NAME ? 1 : 0) << 1) | \
|
||||
(X.name_id == TT_NAME_ID_PREFERRED_FAMILY ? 1 : 0)
|
||||
#else
|
||||
#define GET_NAME_RANK(X) \
|
||||
((IS_PREFERRED_ENC(X) ? 1 : 0) << 1) | \
|
||||
(X.name_id == TT_NAME_ID_PREFERRED_FAMILY ? 1 : 0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return a UTF-8 encoded string given a TrueType name buf+len
|
||||
* and its platform and encoding
|
||||
*/
|
||||
|
||||
char *
|
||||
to_utf8(FT_Byte* buf, FT_UInt len, FT_UShort pid, FT_UShort eid) {
|
||||
size_t ret_len = len * 4; // max chars in a utf8 string
|
||||
char *ret = (char*)malloc(ret_len + 1); // utf8 string + null
|
||||
|
||||
if (!ret) return NULL;
|
||||
|
||||
// In my testing of hundreds of fonts from the Google Font repo, the two types
|
||||
// of fonts are TT_PLATFORM_MICROSOFT with TT_MS_ID_UNICODE_CS encoding, or
|
||||
// TT_PLATFORM_MACINTOSH with TT_MAC_ID_ROMAN encoding. Usually both, never neither
|
||||
|
||||
char const *fromcode;
|
||||
|
||||
if (pid == TT_PLATFORM_MACINTOSH && eid == TT_MAC_ID_ROMAN) {
|
||||
fromcode = "MAC";
|
||||
} else if (pid == TT_PLATFORM_MICROSOFT && eid == TT_MS_ID_UNICODE_CS) {
|
||||
fromcode = "UTF-16BE";
|
||||
} else {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GIConv cd = g_iconv_open("UTF-8", fromcode);
|
||||
|
||||
if (cd == (GIConv)-1) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t inbytesleft = len;
|
||||
size_t outbytesleft = ret_len;
|
||||
|
||||
size_t n_converted = g_iconv(cd, (char**)&buf, &inbytesleft, &ret, &outbytesleft);
|
||||
|
||||
ret -= ret_len - outbytesleft; // rewind the pointers to their
|
||||
buf -= len - inbytesleft; // original starting positions
|
||||
|
||||
if (n_converted == (size_t)-1) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
} else {
|
||||
ret[ret_len - outbytesleft] = '\0';
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a family name in the face's name table, preferring the one the
|
||||
* system, fall back to the other
|
||||
*/
|
||||
|
||||
char *
|
||||
get_family_name(FT_Face face) {
|
||||
FT_SfntName name;
|
||||
|
||||
int best_rank = -1;
|
||||
char* best_buf = NULL;
|
||||
|
||||
for (unsigned i = 0; i < FT_Get_Sfnt_Name_Count(face); ++i) {
|
||||
FT_Get_Sfnt_Name(face, i, &name);
|
||||
|
||||
if (
|
||||
name.name_id == TT_NAME_ID_FONT_FAMILY ||
|
||||
#ifdef PERFECT_MATCHES_ENABLED
|
||||
name.name_id == TT_NAME_ID_PS_NAME ||
|
||||
#endif
|
||||
name.name_id == TT_NAME_ID_PREFERRED_FAMILY
|
||||
) {
|
||||
int rank = GET_NAME_RANK(name);
|
||||
|
||||
if (rank > best_rank) {
|
||||
char *buf = to_utf8(name.string, name.string_len, name.platform_id, name.encoding_id);
|
||||
if (buf) {
|
||||
best_rank = rank;
|
||||
if (best_buf) free(best_buf);
|
||||
best_buf = buf;
|
||||
|
||||
#ifdef PERFECT_MATCHES_ENABLED
|
||||
// Prepend an '@' to the postscript name
|
||||
if (name.name_id == TT_NAME_ID_PS_NAME) {
|
||||
std::string best_buf_modified = "@";
|
||||
best_buf_modified += best_buf;
|
||||
free(best_buf);
|
||||
best_buf = strdup(best_buf_modified.c_str());
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return best_buf;
|
||||
}
|
||||
|
||||
PangoWeight
|
||||
get_pango_weight(FT_UShort weight) {
|
||||
switch (weight) {
|
||||
case 100: return PANGO_WEIGHT_THIN;
|
||||
case 200: return PANGO_WEIGHT_ULTRALIGHT;
|
||||
case 300: return PANGO_WEIGHT_LIGHT;
|
||||
#if PANGO_VERSION >= PANGO_VERSION_ENCODE(1, 36, 7)
|
||||
case 350: return PANGO_WEIGHT_SEMILIGHT;
|
||||
#endif
|
||||
case 380: return PANGO_WEIGHT_BOOK;
|
||||
case 400: return PANGO_WEIGHT_NORMAL;
|
||||
case 500: return PANGO_WEIGHT_MEDIUM;
|
||||
case 600: return PANGO_WEIGHT_SEMIBOLD;
|
||||
case 700: return PANGO_WEIGHT_BOLD;
|
||||
case 800: return PANGO_WEIGHT_ULTRABOLD;
|
||||
case 900: return PANGO_WEIGHT_HEAVY;
|
||||
case 1000: return PANGO_WEIGHT_ULTRAHEAVY;
|
||||
default: return PANGO_WEIGHT_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
PangoStretch
|
||||
get_pango_stretch(FT_UShort width) {
|
||||
switch (width) {
|
||||
case 1: return PANGO_STRETCH_ULTRA_CONDENSED;
|
||||
case 2: return PANGO_STRETCH_EXTRA_CONDENSED;
|
||||
case 3: return PANGO_STRETCH_CONDENSED;
|
||||
case 4: return PANGO_STRETCH_SEMI_CONDENSED;
|
||||
case 5: return PANGO_STRETCH_NORMAL;
|
||||
case 6: return PANGO_STRETCH_SEMI_EXPANDED;
|
||||
case 7: return PANGO_STRETCH_EXPANDED;
|
||||
case 8: return PANGO_STRETCH_EXTRA_EXPANDED;
|
||||
case 9: return PANGO_STRETCH_ULTRA_EXPANDED;
|
||||
default: return PANGO_STRETCH_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
PangoStyle
|
||||
get_pango_style(FT_Long flags) {
|
||||
if (flags & FT_STYLE_FLAG_ITALIC) {
|
||||
return PANGO_STYLE_ITALIC;
|
||||
} else {
|
||||
return PANGO_STYLE_NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
std::unique_ptr<wchar_t[]>
|
||||
u8ToWide(const char* str) {
|
||||
int iBufferSize = MultiByteToWideChar(CP_UTF8, 0, str, -1, (wchar_t*)NULL, 0);
|
||||
if(!iBufferSize){
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<wchar_t[]> wpBufWString = std::unique_ptr<wchar_t[]>{ new wchar_t[static_cast<size_t>(iBufferSize)] };
|
||||
if(!MultiByteToWideChar(CP_UTF8, 0, str, -1, wpBufWString.get(), iBufferSize)){
|
||||
return nullptr;
|
||||
}
|
||||
return wpBufWString;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
stream_read_func(FT_Stream stream, unsigned long offset, unsigned char* buffer, unsigned long count){
|
||||
HANDLE hFile = reinterpret_cast<HANDLE>(stream->descriptor.pointer);
|
||||
DWORD numberOfBytesRead;
|
||||
OVERLAPPED overlapped;
|
||||
overlapped.Offset = offset;
|
||||
overlapped.OffsetHigh = 0;
|
||||
overlapped.hEvent = NULL;
|
||||
if(!ReadFile(hFile, buffer, count, &numberOfBytesRead, &overlapped)){
|
||||
return 0;
|
||||
}
|
||||
return numberOfBytesRead;
|
||||
};
|
||||
|
||||
static void
|
||||
stream_close_func(FT_Stream stream){
|
||||
HANDLE hFile = reinterpret_cast<HANDLE>(stream->descriptor.pointer);
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return a PangoFontDescription that will resolve to the font file
|
||||
*/
|
||||
|
||||
PangoFontDescription *
|
||||
get_pango_font_description(unsigned char* filepath) {
|
||||
FT_Library library;
|
||||
FT_Face face;
|
||||
PangoFontDescription *desc = pango_font_description_new();
|
||||
#ifdef _WIN32
|
||||
// FT_New_Face use fopen.
|
||||
// Unable to find the file when supplied the multibyte string path on the Windows platform and throw error "Could not parse font file".
|
||||
// This workaround fixes this by reading the font file uses win32 wide character API.
|
||||
std::unique_ptr<wchar_t[]> wFilepath = u8ToWide((char*)filepath);
|
||||
if(!wFilepath){
|
||||
return NULL;
|
||||
}
|
||||
HANDLE hFile = CreateFileW(
|
||||
wFilepath.get(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL
|
||||
);
|
||||
if(!hFile){
|
||||
return NULL;
|
||||
}
|
||||
LARGE_INTEGER liSize;
|
||||
if(!GetFileSizeEx(hFile, &liSize)) {
|
||||
CloseHandle(hFile);
|
||||
return NULL;
|
||||
}
|
||||
FT_Open_Args args;
|
||||
args.flags = FT_OPEN_STREAM;
|
||||
FT_StreamRec stream;
|
||||
stream.base = NULL;
|
||||
stream.size = liSize.QuadPart;
|
||||
stream.pos = 0;
|
||||
stream.descriptor.pointer = hFile;
|
||||
stream.read = stream_read_func;
|
||||
stream.close = stream_close_func;
|
||||
args.stream = &stream;
|
||||
if (
|
||||
!FT_Init_FreeType(&library) &&
|
||||
!FT_Open_Face(library, &args, 0, &face)) {
|
||||
#else
|
||||
if (!FT_Init_FreeType(&library) && !FT_New_Face(library, (const char*)filepath, 0, &face)) {
|
||||
#endif
|
||||
TT_OS2 *table = (TT_OS2*)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
|
||||
if (table) {
|
||||
char *family = get_family_name(face);
|
||||
|
||||
if (!family) {
|
||||
pango_font_description_free(desc);
|
||||
FT_Done_Face(face);
|
||||
FT_Done_FreeType(library);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pango_font_description_set_family_static(desc, family);
|
||||
pango_font_description_set_weight(desc, get_pango_weight(table->usWeightClass));
|
||||
pango_font_description_set_stretch(desc, get_pango_stretch(table->usWidthClass));
|
||||
pango_font_description_set_style(desc, get_pango_style(face->style_flags));
|
||||
|
||||
FT_Done_Face(face);
|
||||
FT_Done_FreeType(library);
|
||||
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
pango_font_description_free(desc);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef PERFECT_MATCHES_ENABLED
|
||||
static void
|
||||
fc_font_map_substitute_hook(FcPattern *pat, gpointer data) {
|
||||
FcChar8 *family;
|
||||
|
||||
for (int i = 0; FcPatternGetString(pat, FC_FAMILY, i, &family) == FcResultMatch; i++) {
|
||||
if (family[0] == '@') {
|
||||
FcPatternAddString(pat, FC_POSTSCRIPT_NAME, (FcChar8 *)family + 1);
|
||||
FcPatternRemove(pat, FC_FAMILY, i);
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Register font with the OS
|
||||
*/
|
||||
|
||||
bool
|
||||
register_font(unsigned char *filepath) {
|
||||
bool success;
|
||||
|
||||
#ifdef __APPLE__
|
||||
CFURLRef filepathUrl = CFURLCreateFromFileSystemRepresentation(NULL, filepath, strlen((char*)filepath), false);
|
||||
success = CTFontManagerRegisterFontsForURL(filepathUrl, kCTFontManagerScopeProcess, NULL);
|
||||
#elif defined(_WIN32)
|
||||
std::unique_ptr<wchar_t[]> wFilepath = u8ToWide((char*)filepath);
|
||||
if(wFilepath){
|
||||
success = AddFontResourceExW(wFilepath.get(), FR_PRIVATE, 0) != 0;
|
||||
}else{
|
||||
success = false;
|
||||
}
|
||||
|
||||
#else
|
||||
success = FcConfigAppFontAddFile(FcConfigGetCurrent(), (FcChar8 *)(filepath));
|
||||
#endif
|
||||
|
||||
if (!success) return false;
|
||||
|
||||
// Tell Pango to throw away the current FontMap and create a new one. This
|
||||
// has the effect of registering the new font in Pango by re-looking up all
|
||||
// font families.
|
||||
pango_cairo_font_map_set_default(NULL);
|
||||
|
||||
#ifdef PERFECT_MATCHES_ENABLED
|
||||
PangoFontMap* map = pango_cairo_font_map_get_default();
|
||||
PangoFcFontMap* fc_map = PANGO_FC_FONT_MAP(map);
|
||||
pango_fc_font_map_set_default_substitute(fc_map, fc_font_map_substitute_hook, NULL, NULL);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deregister font from the OS
|
||||
* Note that Linux (FontConfig) can only dereregister ALL fonts at once.
|
||||
*/
|
||||
|
||||
bool
|
||||
deregister_font(unsigned char *filepath) {
|
||||
bool success;
|
||||
|
||||
#ifdef __APPLE__
|
||||
CFURLRef filepathUrl = CFURLCreateFromFileSystemRepresentation(NULL, filepath, strlen((char*)filepath), false);
|
||||
success = CTFontManagerUnregisterFontsForURL(filepathUrl, kCTFontManagerScopeProcess, NULL);
|
||||
#elif defined(_WIN32)
|
||||
std::unique_ptr<wchar_t[]> wFilepath = u8ToWide((char*)filepath);
|
||||
if(wFilepath){
|
||||
success = RemoveFontResourceExW(wFilepath.get(), FR_PRIVATE, 0) != 0;
|
||||
}else{
|
||||
success = false;
|
||||
}
|
||||
#else
|
||||
FcConfigAppFontClear(FcConfigGetCurrent());
|
||||
success = true;
|
||||
#endif
|
||||
|
||||
if (!success) return false;
|
||||
|
||||
// Tell Pango to throw away the current FontMap and create a new one. This
|
||||
// has the effect of deregistering the font in Pango by re-looking up all
|
||||
// font families.
|
||||
pango_cairo_font_map_set_default(NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
7
npm-packages/mac-v2.4.x/canvas/src/register_font.h
Normal file
7
npm-packages/mac-v2.4.x/canvas/src/register_font.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <pango/pango.h>
|
||||
|
||||
PangoFontDescription *get_pango_font_description(unsigned char *filepath);
|
||||
bool register_font(unsigned char *filepath);
|
||||
bool deregister_font(unsigned char *filepath);
|
||||
Reference in New Issue
Block a user