Skip to content

Commit

Permalink
refactor: refactor event and document.
Browse files Browse the repository at this point in the history
  • Loading branch information
andycall committed Jan 24, 2022
1 parent 3449e36 commit d80b528
Show file tree
Hide file tree
Showing 22 changed files with 646 additions and 493 deletions.
142 changes: 64 additions & 78 deletions bridge/bindings/qjs/bom/blob.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,90 +8,74 @@

namespace kraken::binding::qjs {

std::once_flag kBlobInitOnceFlag;

void bindBlob(std::unique_ptr<ExecutionContext>& context) {
auto* constructor = Blob::instance(context.get());
context->defineGlobalProperty("Blob", constructor->jsObject);
}

Blob::Blob(ExecutionContext* context) : HostClass(context, "Blob") {
std::call_once(kBlobInitOnceFlag, []() { JS_NewClassID(&kBlobClassID); });
}

JSClassID Blob::kBlobClassID{0};

JSValue Blob::instanceConstructor(JSContext* ctx, JSValue func_obj, JSValue this_val, int argc, JSValue* argv) {
BlobBuilder builder;
auto constructor = static_cast<Blob*>(JS_GetOpaque(func_obj, ExecutionContext::kHostClassClassId));
if (argc == 0) {
auto blob = new BlobInstance(constructor);
return blob->jsObject;
}
JSValue constructor = context->contextData()->constructorForType(&blobTypeInfo);
JSValue prototype = context->contextData()->prototypeForType(&blobTypeInfo);

JSValue arrayValue = argv[0];
JSValue optionValue = JS_UNDEFINED;
// Install methods on prototype.
INSTALL_FUNCTION(Blob, prototype, arrayBuffer, 0);
INSTALL_FUNCTION(Blob, prototype, slice, 3);
INSTALL_FUNCTION(Blob, prototype, text, 0);

if (argc > 1) {
optionValue = argv[1];
}
// Install readonly properties.
INSTALL_READONLY_PROPERTY(Blob, prototype, type);
INSTALL_READONLY_PROPERTY(Blob, prototype, size);

if (!JS_IsArray(ctx, arrayValue)) {
return JS_ThrowTypeError(ctx, "Failed to construct 'Blob': The provided value cannot be converted to a sequence");
}
context->defineGlobalProperty("Blob", constructor);
}

if (argc == 1 || JS_IsUndefined(optionValue)) {
builder.append(*constructor->m_context, arrayValue);
auto blob = new BlobInstance(constructor, builder.finalize());
return blob->jsObject;
}
JSClassID Blob::classID{0};

if (!JS_IsObject(optionValue)) {
return JS_ThrowTypeError(ctx,
"Failed to construct 'Blob': parameter 2 ('options') "
"is not an object");
}
Blob* Blob::create(JSContext* ctx) {
auto* context = static_cast<ExecutionContext*>(JS_GetContextOpaque(ctx));
auto* blob = makeGarbageCollected<Blob>()->initialize<Blob>(ctx, &classID);

JSAtom mimeTypeKey = JS_NewAtom(ctx, "type");
JSValue prototype = context->contextData()->prototypeForType(&blobTypeInfo);

JSValue mimeTypeValue = JS_GetProperty(ctx, optionValue, mimeTypeKey);
builder.append(*constructor->m_context, mimeTypeValue);
const char* cMineType = JS_ToCString(ctx, mimeTypeValue);
std::string mimeType = std::string(cMineType);
// Let eventTarget instance inherit EventTarget prototype methods.
JS_SetPrototype(ctx, blob->toQuickJS(), prototype);
return blob;

auto* blob = new BlobInstance(constructor, builder.finalize(), mimeType);
}
Blob* Blob::create(JSContext* ctx, std::vector<uint8_t>&& data) {
return create(ctx);
}
Blob* Blob::create(JSContext* ctx, std::vector<uint8_t>&& data, std::string& mime) {
return create(ctx);
}

JS_FreeValue(ctx, mimeTypeValue);
JS_FreeCString(ctx, mimeType.c_str());
JS_FreeAtom(ctx, mimeTypeKey);
JSValue Blob::constructor(ExecutionContext* context) {
return context->contextData()->constructorForType(&blobTypeInfo);
}

return blob->jsObject;
JSValue Blob::prototype(ExecutionContext* context) {
return context->contextData()->prototypeForType(&blobTypeInfo);
}

IMPL_PROPERTY_GETTER(Blob, type)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
auto* blobInstance = static_cast<BlobInstance*>(JS_GetOpaque(this_val, Blob::kBlobClassID));
return JS_NewString(blobInstance->m_ctx, blobInstance->mimeType.empty() ? "" : blobInstance->mimeType.c_str());
auto* blob = static_cast<Blob*>(JS_GetOpaque(this_val, Blob::classID));
return JS_NewString(blob->m_ctx, blob->mimeType.empty() ? "" : blob->mimeType.c_str());
}

IMPL_PROPERTY_GETTER(Blob, size)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
auto* blobInstance = static_cast<BlobInstance*>(JS_GetOpaque(this_val, Blob::kBlobClassID));
return JS_NewFloat64(blobInstance->m_ctx, blobInstance->_size);
auto* blob = static_cast<Blob*>(JS_GetOpaque(this_val, Blob::classID));
return JS_NewFloat64(blob->m_ctx, blob->_size);
}

JSValue Blob::arrayBuffer(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
IMPL_FUNCTION(Blob, arrayBuffer)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
JSValue resolving_funcs[2];
JSValue promise = JS_NewPromiseCapability(ctx, resolving_funcs);

auto blob = static_cast<BlobInstance*>(JS_GetOpaque(this_val, Blob::kBlobClassID));
auto blob = static_cast<Blob*>(JS_GetOpaque(this_val, Blob::classID));

JS_DupValue(ctx, blob->jsObject);

auto* promiseContext = new PromiseContext{blob, blob->m_context, resolving_funcs[0], resolving_funcs[1], promise};
auto* promiseContext = new PromiseContext{blob, blob->context(), resolving_funcs[0], resolving_funcs[1], promise};
auto callback = [](void* callbackContext, int32_t contextId, const char* errmsg) {
if (!isContextValid(contextId))
return;
auto* promiseContext = static_cast<PromiseContext*>(callbackContext);
auto* blob = static_cast<BlobInstance*>(promiseContext->data);
auto* blob = static_cast<Blob*>(promiseContext->data);
JSContext* ctx = blob->m_ctx;

JSValue arrayBuffer = JS_NewArrayBuffer(
Expand All @@ -114,20 +98,20 @@ JSValue Blob::arrayBuffer(JSContext* ctx, JSValue this_val, int argc, JSValue* a
list_del(&promiseContext->link);
delete promiseContext;
};
list_add_tail(&promiseContext->link, &blob->m_context->promise_job_list);
list_add_tail(&promiseContext->link, &blob->context()->promise_job_list);

// TODO: remove setTimeout
getDartMethod()->setTimeout(promiseContext, blob->context()->getContextId(), callback, 0);

return promise;
}

JSValue Blob::slice(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
IMPL_FUNCTION(Blob, slice)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
JSValue startValue = argv[0];
JSValue endValue = argv[1];
JSValue contentTypeValue = argv[2];

auto* blob = static_cast<BlobInstance*>(JS_GetOpaque(this_val, Blob::kBlobClassID));
auto* blob = static_cast<Blob*>(JS_GetOpaque(this_val, Blob::classID));
int32_t start = 0;
int32_t end = blob->_data.size();
std::string mimeType = blob->mimeType;
Expand All @@ -147,31 +131,31 @@ JSValue Blob::slice(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
}

if (start == 0 && end == blob->_data.size()) {
auto newBlob = new BlobInstance(reinterpret_cast<Blob*>(blob->m_hostClass), std::move(blob->_data), mimeType);
return newBlob->jsObject;
auto* newBlob = Blob::create(ctx, std::move(blob->_data), mimeType);
return newBlob->toQuickJS();
}
std::vector<uint8_t> newData;
newData.reserve(blob->_data.size() - (end - start));
newData.insert(newData.begin(), blob->_data.begin() + start, blob->_data.end() - (blob->_data.size() - end));

auto newBlob = new BlobInstance(reinterpret_cast<Blob*>(blob->m_hostClass), std::move(newData), mimeType);
return newBlob->jsObject;
auto* newBlob = Blob::create(ctx, std::move(newData), mimeType);
return newBlob->toQuickJS();
}

JSValue Blob::text(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
IMPL_FUNCTION(Blob, text)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
JSValue resolving_funcs[2];
JSValue promise = JS_NewPromiseCapability(ctx, resolving_funcs);

auto blob = static_cast<BlobInstance*>(JS_GetOpaque(this_val, Blob::kBlobClassID));
auto blob = static_cast<Blob*>(JS_GetOpaque(this_val, Blob::classID));
JS_DupValue(ctx, blob->jsObject);

auto* promiseContext = new PromiseContext{blob, blob->m_context, resolving_funcs[0], resolving_funcs[1], promise};
auto* promiseContext = new PromiseContext{blob, blob->context(), resolving_funcs[0], resolving_funcs[1], promise};
auto callback = [](void* callbackContext, int32_t contextId, const char* errmsg) {
if (!isContextValid(contextId))
return;

auto* promiseContext = static_cast<PromiseContext*>(callbackContext);
auto* blob = static_cast<BlobInstance*>(promiseContext->data);
auto* blob = static_cast<Blob*>(promiseContext->data);
JSContext* ctx = blob->m_ctx;

JSValue text = JS_NewStringLen(ctx, reinterpret_cast<const char*>(blob->bytes()), blob->size());
Expand All @@ -193,19 +177,14 @@ JSValue Blob::text(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
list_del(&promiseContext->link);
delete promiseContext;
};
list_add_tail(&promiseContext->link, &blob->m_context->promise_job_list);
list_add_tail(&promiseContext->link, &blob->context()->promise_job_list);

getDartMethod()->setTimeout(promiseContext, blob->context()->getContextId(), callback, 0);

return promise;
}

void BlobInstance::finalize(JSRuntime* rt, JSValue val) {
auto* eventTarget = static_cast<BlobInstance*>(JS_GetOpaque(val, Blob::kBlobClassID));
delete eventTarget;
}

void BlobBuilder::append(ExecutionContext& context, BlobInstance* blob) {
void BlobBuilder::append(ExecutionContext& context, Blob* blob) {
std::vector<uint8_t> blobData = blob->_data;
_data.reserve(_data.size() + blobData.size());
_data.insert(_data.end(), blobData.begin(), blobData.end());
Expand Down Expand Up @@ -234,11 +213,11 @@ void BlobBuilder::append(ExecutionContext& context, JSValue& value) {
JS_FreeValue(context.ctx(), v);
}
} else if (JS_IsObject(value)) {
if (JS_IsInstanceOf(context.ctx(), value, Blob::instance(&context)->jsObject)) {
auto blob = static_cast<BlobInstance*>(JS_GetOpaque(value, Blob::kBlobClassID));
if (JS_IsInstanceOf(context.ctx(), value, Blob::constructor(&context))) {
auto blob = static_cast<Blob*>(JS_GetOpaque(value, Blob::classID));
if (blob == nullptr)
return;
if (std::string(blob->m_name) == "Blob") {
if (std::string(blob->getHumanReadableName()) == "Blob") {
std::vector<uint8_t> blobData = blob->_data;
_data.reserve(_data.size() + blobData.size());
_data.insert(_data.end(), blobData.begin(), blobData.end());
Expand Down Expand Up @@ -271,11 +250,18 @@ std::vector<uint8_t> BlobBuilder::finalize() {
return std::move(_data);
}

int32_t BlobInstance::size() {
int32_t Blob::size() {
return _data.size();
}

uint8_t* BlobInstance::bytes() {
uint8_t* Blob::bytes() {
return _data.data();
}

void Blob::trace(JSRuntime* rt, JSValue val, JS_MarkFunc* mark_func) const {}
void Blob::dispose() const {

}


} // namespace kraken::binding::qjs
108 changes: 75 additions & 33 deletions bridge/bindings/qjs/bom/blob.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,57 +15,45 @@ class BlobInstance;

void bindBlob(std::unique_ptr<ExecutionContext>& context);

class Blob : public HostClass {
class Blob : public GarbageCollected<Blob> {
public:
static JSClassID kBlobClassID;
OBJECT_INSTANCE(Blob);
static JSClassID classID;
static Blob* create(JSContext* ctx);
static Blob* create(JSContext* ctx, std::vector<uint8_t>&& data);
static Blob* create(JSContext* ctx, std::vector<uint8_t>&& data, std::string& mime);
static JSValue constructor(ExecutionContext* context);
static JSValue prototype(ExecutionContext* context);

Blob() = delete;
explicit Blob(ExecutionContext* context);
Blob() {};
Blob(std::vector<uint8_t>&& data): _size(data.size()), _data(std::move(data)) {};
Blob(std::vector<uint8_t>&& data, std::string& mime): mimeType(mime), _size(data.size()), _data(std::move(data)) {};

JSValue instanceConstructor(JSContext* ctx, JSValue func_obj, JSValue this_val, int argc, JSValue* argv) override;

static JSValue arrayBuffer(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
static JSValue slice(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
static JSValue text(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);

private:
friend BlobInstance;
DEFINE_PROTOTYPE_READONLY_PROPERTY(type);
DEFINE_PROTOTYPE_READONLY_PROPERTY(size);

DEFINE_PROTOTYPE_FUNCTION(arrayBuffer, 0);
DEFINE_PROTOTYPE_FUNCTION(slice, 3);
DEFINE_PROTOTYPE_FUNCTION(text, 0);
};

class BlobInstance : public Instance {
public:
BlobInstance() = delete;
explicit BlobInstance(Blob* blob) : Instance(blob, "Blob", nullptr, Blob::kBlobClassID, finalize){};
explicit BlobInstance(Blob* blob, std::vector<uint8_t>&& data) : _size(data.size()), _data(std::move(data)), Instance(blob, "Blob", nullptr, Blob::kBlobClassID, finalize){};
explicit BlobInstance(Blob* blob, std::vector<uint8_t>&& data, std::string& mime)
: mimeType(mime), _size(data.size()), _data(std::move(data)), Instance(blob, "Blob", nullptr, Blob::kBlobClassID, finalize){};
DEFINE_FUNCTION(arrayBuffer);
DEFINE_FUNCTION(slice);
DEFINE_FUNCTION(text);

/// get an pointer of bytes data from JSBlob
uint8_t* bytes();
/// get bytes data's length
int32_t size();

DEFINE_PROTOTYPE_READONLY_PROPERTY(type);
DEFINE_PROTOTYPE_READONLY_PROPERTY(size);

void trace(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func) const override;
void dispose() const override;

private:
size_t _size;
std::string mimeType{""};
std::string mimeType;
std::vector<uint8_t> _data;
friend BlobBuilder;
friend Blob;

static void finalize(JSRuntime* rt, JSValue val);
};

class BlobBuilder {
public:
void append(ExecutionContext& context, JSValue& value);
void append(ExecutionContext& context, BlobInstance* blob);
void append(ExecutionContext& context, Blob* blob);

std::vector<uint8_t> finalize();

Expand All @@ -74,6 +62,60 @@ class BlobBuilder {
std::vector<uint8_t> _data;
};

auto blobCreator = [](JSContext* ctx, JSValueConst func_obj, JSValueConst this_val, int argc, JSValueConst* argv, int flags) -> JSValue {
if (argc == 0) {
auto* blob = Blob::create(ctx);
return blob->toQuickJS();
}

JSValue arrayValue = argv[0];
JSValue optionValue = JS_UNDEFINED;

if (argc > 1) {
optionValue = argv[1];
}

if (!JS_IsArray(ctx, arrayValue)) {
return JS_ThrowTypeError(ctx, "Failed to construct 'Blob': The provided value cannot be converted to a sequence");
}

auto* context = static_cast<ExecutionContext*>(JS_GetContextOpaque(ctx));
BlobBuilder builder;

if (argc == 1 || JS_IsUndefined(optionValue)) {
builder.append(*context, arrayValue);
auto* blob = Blob::create(ctx, builder.finalize());
return blob->toQuickJS();
}

if (!JS_IsObject(optionValue)) {
return JS_ThrowTypeError(ctx,
"Failed to construct 'Blob': parameter 2 ('options') "
"is not an object");
}

JSAtom mimeTypeKey = JS_NewAtom(ctx, "type");

JSValue mimeTypeValue = JS_GetProperty(ctx, optionValue, mimeTypeKey);
builder.append(*context, mimeTypeValue);
const char* cMineType = JS_ToCString(ctx, mimeTypeValue);
std::string mimeType = std::string(cMineType);

auto* blob = Blob::create(ctx, builder.finalize(), mimeType);

JS_FreeValue(ctx, mimeTypeValue);
JS_FreeCString(ctx, mimeType.c_str());
JS_FreeAtom(ctx, mimeTypeKey);

return blob->toQuickJS();
};

const WrapperTypeInfo blobTypeInfo = {
"Blob",
nullptr,
blobCreator
};

} // namespace kraken::binding::qjs

#endif // KRAKENBRIDGE_BLOB_H
Loading

0 comments on commit d80b528

Please sign in to comment.