aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2023-08-19 17:46:59 -0700
committerGravatar GitHub <noreply@github.com> 2023-08-19 17:46:59 -0700
commit196620183fd20ca42b363c5f947af1dc979f888f (patch)
tree2413e721e515588eb743358df6a4a4f3750572d8
parent86ad0151479c96314233c2d7dfbf7ed83b57feab (diff)
downloadbun-196620183fd20ca42b363c5f947af1dc979f888f.tar.gz
bun-196620183fd20ca42b363c5f947af1dc979f888f.tar.zst
bun-196620183fd20ca42b363c5f947af1dc979f888f.zip
Fixes #172 (#4220)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
-rw-r--r--.vscode/c_cpp_properties.json3
-rw-r--r--src/bun.js/bindings/napi.cpp19
-rw-r--r--src/bun.js/bindings/napi.h14
-rwxr-xr-xtest/bun.lockbbin148448 -> 153753 bytes
-rw-r--r--test/js/third_party/resvg/bbox.test.js53
-rw-r--r--test/js/third_party/resvg/package.json6
-rw-r--r--test/package.json1
7 files changed, 87 insertions, 9 deletions
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
index 01081421f..8036312a6 100644
--- a/.vscode/c_cpp_properties.json
+++ b/.vscode/c_cpp_properties.json
@@ -20,6 +20,7 @@
"${workspaceFolder}/src/js/out",
"${workspaceFolder}/src/deps/boringssl/include/",
"${workspaceFolder}/src/deps",
+ "${workspaceFolder}/src/napi/*",
"${workspaceFolder}/src/deps/uws/uSockets/src"
],
"browse": {
@@ -32,6 +33,8 @@
"${workspaceFolder}/src/bun.js/WebKit/WebKitBuild/Release/WTF/Headers/**",
"${workspaceFolder}/src/bun.js/WebKit/WebKitBuild/Release/bmalloc/Headers/**",
"${workspaceFolder}/src/bun.js/bindings/*",
+ "${workspaceFolder}/src/bun.js/bindings/*",
+ "${workspaceFolder}/src/napi/*",
"${workspaceFolder}/src/bun.js/bindings/sqlite/",
"${workspaceFolder}/src/bun.js/bindings/webcrypto/",
"${workspaceFolder}/src/bun.js/bindings/webcore/",
diff --git a/src/bun.js/bindings/napi.cpp b/src/bun.js/bindings/napi.cpp
index d532e5444..237f3d554 100644
--- a/src/bun.js/bindings/napi.cpp
+++ b/src/bun.js/bindings/napi.cpp
@@ -1244,18 +1244,30 @@ JSC_DEFINE_HOST_FUNCTION(NapiClass_ConstructorFunction,
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
-
+ JSObject* constructorTarget = asObject(callFrame->jsCallee());
JSObject* newTarget = asObject(callFrame->newTarget());
+ NapiClass* napi = jsDynamicCast<NapiClass*>(constructorTarget);
+ while (!napi && constructorTarget) {
+ constructorTarget = constructorTarget->getPrototypeDirect().getObject();
+ napi = jsDynamicCast<NapiClass*>(constructorTarget);
+ }
- NapiClass* napi = jsDynamicCast<NapiClass*>(newTarget);
if (UNLIKELY(!napi)) {
JSC::throwVMError(globalObject, scope, JSC::createTypeError(globalObject, "NapiClass constructor called on an object that is not a NapiClass"_s));
return JSC::JSValue::encode(JSC::jsUndefined());
}
- NapiPrototype* prototype = JSC::jsDynamicCast<NapiPrototype*>(napi->getDirect(vm, vm.propertyNames->prototype));
+ NapiPrototype* prototype = JSC::jsDynamicCast<NapiPrototype*>(napi->getIfPropertyExists(globalObject, vm.propertyNames->prototype));
+ RETURN_IF_EXCEPTION(scope, {});
+
+ if (!prototype) {
+ JSC::throwVMError(globalObject, scope, JSC::createTypeError(globalObject, "NapiClass constructor is missing the prototype"_s));
+ return JSC::JSValue::encode(JSC::jsUndefined());
+ }
+ auto* subclass = prototype->subclass(globalObject, newTarget);
RETURN_IF_EXCEPTION(scope, {});
+ callFrame->setThisValue(subclass);
size_t count = callFrame->argumentCount();
MarkedArgumentBuffer args;
@@ -1266,7 +1278,6 @@ JSC_DEFINE_HOST_FUNCTION(NapiClass_ConstructorFunction,
}
}
- callFrame->setThisValue(prototype->subclass(newTarget));
napi->constructor()(globalObject, callFrame);
RETURN_IF_EXCEPTION(scope, {});
diff --git a/src/bun.js/bindings/napi.h b/src/bun.js/bindings/napi.h
index 550803963..b157c4367 100644
--- a/src/bun.js/bindings/napi.h
+++ b/src/bun.js/bindings/napi.h
@@ -213,15 +213,19 @@ public:
return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}
- NapiPrototype* subclass(JSC::JSObject* newTarget)
+ NapiPrototype* subclass(JSC::JSGlobalObject* globalObject, JSC::JSObject* newTarget)
{
auto& vm = this->vm();
- auto* structure = InternalFunction::createSubclassStructure(globalObject(),
- newTarget,
- this->structure());
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ auto* targetFunction = jsCast<JSFunction*>(newTarget);
+ FunctionRareData* rareData = targetFunction->ensureRareData(vm);
+ auto* prototype = newTarget->get(globalObject, vm.propertyNames->prototype).getObject();
+ RETURN_IF_EXCEPTION(scope, nullptr);
+ auto* structure = rareData->createInternalFunctionAllocationStructureFromBase(vm, globalObject, prototype, this->structure());
+ RETURN_IF_EXCEPTION(scope, nullptr);
NapiPrototype* footprint = new (NotNull, allocateCell<NapiPrototype>(vm)) NapiPrototype(vm, structure);
footprint->finishCreation(vm);
- return footprint;
+ RELEASE_AND_RETURN(scope, footprint);
}
NapiRef* napiRef = nullptr;
diff --git a/test/bun.lockb b/test/bun.lockb
index 01383ce5d..98c35844d 100755
--- a/test/bun.lockb
+++ b/test/bun.lockb
Binary files differ
diff --git a/test/js/third_party/resvg/bbox.test.js b/test/js/third_party/resvg/bbox.test.js
new file mode 100644
index 000000000..d80e99cdd
--- /dev/null
+++ b/test/js/third_party/resvg/bbox.test.js
@@ -0,0 +1,53 @@
+import { test, expect } from "bun:test";
+import { Resvg } from "@resvg/resvg-js";
+
+const svg = `<svg viewBox="-40 0 180 260" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g fill="green" transform="rotate(-10 50 100) translate(-36 45.5) skewX(40) scale(1 0.5)">
+ <path id="heart" d="M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z" />
+</g>
+<use xlink:href="#heart" fill="none" stroke="red" stroke-width="1" />
+</svg>`;
+for (let Class of [
+ Resvg,
+ // Test that subclasses work as well.
+ class ResvgSubclass extends Resvg {
+ constructor(...args) {
+ super(...args);
+ }
+ iShouldExist() {
+ return true;
+ }
+ },
+]) {
+ test(`bbox ${Class.name}`, () => {
+ const opts = {
+ fitTo: {
+ mode: "width",
+ value: 500,
+ },
+ font: {
+ loadSystemFonts: false,
+ },
+ };
+
+ const resvg = new Class(svg, opts);
+ const bbox = resvg.getBBox();
+
+ expect(resvg.width).toBe(180);
+ expect(resvg.height).toBe(260);
+
+ if (bbox) resvg.cropByBBox(bbox);
+ const pngData = resvg.render();
+
+ expect(bbox.width).toBe(112.20712208389321);
+ expect(bbox.height).toBe(81);
+
+ expect(pngData.width).toBe(500);
+ expect(pngData.height).toBe(362);
+
+ if (Class !== Resvg) {
+ expect(resvg).toHaveProperty("iShouldExist");
+ expect(resvg.iShouldExist()).toBeTrue();
+ }
+ });
+}
diff --git a/test/js/third_party/resvg/package.json b/test/js/third_party/resvg/package.json
new file mode 100644
index 000000000..932f36221
--- /dev/null
+++ b/test/js/third_party/resvg/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "bun-integration-test-resvg",
+ "dependencies": {
+ "@resvg/resvg-js": "2.4.1"
+ }
+}
diff --git a/test/package.json b/test/package.json
index 7d8156aa0..f841d2003 100644
--- a/test/package.json
+++ b/test/package.json
@@ -25,6 +25,7 @@
"pg-connection-string": "2.6.1",
"postgres": "3.3.5",
"prisma": "5.1.1",
+ "@resvg/resvg-js": "2.4.1",
"socket.io": "4.7.1",
"socket.io-client": "4.7.1",
"supertest": "6.3.3",