tvg format: code refactoring #10

keep neat & clean code,
revise to tvg style naming convention.
This commit is contained in:
Hermet Park 2021-07-21 13:56:50 +09:00 committed by Hermet Park
parent c2ec997db5
commit 87d00b4121
3 changed files with 167 additions and 150 deletions

Binary file not shown.

View file

@ -22,14 +22,17 @@
#ifndef _TVG_BINARY_DESC_H_ #ifndef _TVG_BINARY_DESC_H_
#define _TVG_BINARY_DESC_H_ #define _TVG_BINARY_DESC_H_
//TODO: Need to consider whether uin8_t is enough size for extension... /* TODO: Need to consider whether uin8_t is enough size for extension...
Rather than optimal data, we can use enough size and data compress? */
/* Data types, do not change data types once Tvg Format is officially released, /* Data types, do not change data types once Tvg Format is officially released,
That would occur the abi break. */ That would occur the abi break. */
using TvgBinByte = uint8_t; using TvgBinByte = uint8_t;
using TvgBinTag = uint8_t;
using TvgBinCounter = uint32_t; using TvgBinCounter = uint32_t;
using TvgBinFlag = uint8_t; using TvgBinTag = TvgBinByte;
using TvgBinFlag = TvgBinByte;
//Header //Header
#define TVG_HEADER_SIGNATURE "ThorVG" #define TVG_HEADER_SIGNATURE "ThorVG"

View file

@ -30,6 +30,14 @@
#define SIZE(A) sizeof(A) #define SIZE(A) sizeof(A)
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
static inline TvgBinCounter SERIAL_DONE(TvgBinCounter cnt)
{
return SIZE(TvgBinTag) + SIZE(TvgBinCounter) + cnt;
}
struct Saver::Impl struct Saver::Impl
{ {
@ -50,7 +58,7 @@ struct Saver::Impl
return true; return true;
} }
bool bufferToFile(const std::string& path) bool flushTo(const std::string& path)
{ {
FILE* fp = fopen(path.c_str(), "w+"); FILE* fp = fopen(path.c_str(), "w+");
if (!fp) return false; if (!fp) return false;
@ -77,289 +85,295 @@ struct Saver::Impl
return true; return true;
} }
void writeMemberIndicator(TvgBinTag ind) void writeTag(TvgBinTag tag)
{ {
buffer.grow(SIZE(TvgBinTag)); buffer.grow(SIZE(TvgBinTag));
memcpy(buffer.ptr(), &ind, SIZE(TvgBinTag)); memcpy(buffer.ptr(), &tag, SIZE(TvgBinTag));
buffer.count += SIZE(TvgBinTag); buffer.count += SIZE(TvgBinTag);
} }
void writeMemberDataSize(TvgBinCounter byteCnt) void writeCount(TvgBinCounter cnt)
{ {
buffer.grow(SIZE(TvgBinCounter)); buffer.grow(SIZE(TvgBinCounter));
memcpy(buffer.ptr(), &byteCnt, SIZE(TvgBinCounter)); memcpy(buffer.ptr(), &cnt, SIZE(TvgBinCounter));
buffer.count += SIZE(TvgBinCounter); buffer.count += SIZE(TvgBinCounter);
} }
void writeMemberDataSizeAt(TvgBinCounter byteCnt) void writeReservedCount(TvgBinCounter cnt)
{ {
memcpy(buffer.ptr() - byteCnt - SIZE(TvgBinCounter), &byteCnt, SIZE(TvgBinCounter)); memcpy(buffer.ptr() - cnt - SIZE(TvgBinCounter), &cnt, SIZE(TvgBinCounter));
} }
void skipInBufferMemberDataSize() void reserveCount()
{ {
buffer.grow(SIZE(TvgBinCounter)); buffer.grow(SIZE(TvgBinCounter));
buffer.count += SIZE(TvgBinCounter); buffer.count += SIZE(TvgBinCounter);
} }
TvgBinCounter writeMemberData(const void* data, TvgBinCounter byteCnt) TvgBinCounter writeData(const void* data, TvgBinCounter cnt)
{ {
buffer.grow(byteCnt); buffer.grow(cnt);
memcpy(buffer.ptr(), data, byteCnt); memcpy(buffer.ptr(), data, cnt);
buffer.count += byteCnt; buffer.count += cnt;
return byteCnt; return cnt;
} }
TvgBinCounter writeMember(TvgBinTag ind, TvgBinCounter byteCnt, const void* data) TvgBinCounter writeTagProperty(TvgBinTag tag, TvgBinCounter cnt, const void* data)
{ {
TvgBinCounter blockByteCnt = SIZE(TvgBinTag) + SIZE(TvgBinCounter) + byteCnt; TvgBinCounter growCnt = SERIAL_DONE(cnt);
buffer.grow(blockByteCnt); buffer.grow(growCnt);
auto ptr = buffer.ptr(); auto ptr = buffer.ptr();
memcpy(ptr, &ind, SIZE(TvgBinTag)); *ptr = tag;
ptr += SIZE(TvgBinTag); ++ptr;
memcpy(ptr, &byteCnt, SIZE(TvgBinCounter));
memcpy(ptr, &cnt, SIZE(TvgBinCounter));
ptr += SIZE(TvgBinCounter); ptr += SIZE(TvgBinCounter);
memcpy(ptr, data, byteCnt);
ptr += byteCnt;
buffer.count += blockByteCnt; memcpy(ptr, data, cnt);
ptr += cnt;
return blockByteCnt; buffer.count += growCnt;
return growCnt;
} }
TvgBinCounter serializePaint(const Paint* paint) TvgBinCounter serializePaint(const Paint* paint)
{ {
TvgBinCounter paintDataByteCnt = 0; TvgBinCounter cnt = 0;
//opacity
auto opacity = paint->opacity(); auto opacity = paint->opacity();
if (opacity < 255) { if (opacity < 255) {
paintDataByteCnt += writeMember(TVG_TAG_PAINT_OPACITY, sizeof(opacity), &opacity); cnt += writeTagProperty(TVG_TAG_PAINT_OPACITY, sizeof(opacity), &opacity);
} }
//transform
auto m = const_cast<Paint*>(paint)->transform(); auto m = const_cast<Paint*>(paint)->transform();
if (fabs(m.e11 - 1) > FLT_EPSILON || fabs(m.e12) > FLT_EPSILON || fabs(m.e13) > FLT_EPSILON || if (fabs(m.e11 - 1) > FLT_EPSILON || fabs(m.e12) > FLT_EPSILON || fabs(m.e13) > FLT_EPSILON ||
fabs(m.e21) > FLT_EPSILON || fabs(m.e22 - 1) > FLT_EPSILON || fabs(m.e23) > FLT_EPSILON || fabs(m.e21) > FLT_EPSILON || fabs(m.e22 - 1) > FLT_EPSILON || fabs(m.e23) > FLT_EPSILON ||
fabs(m.e31) > FLT_EPSILON || fabs(m.e32) > FLT_EPSILON || fabs(m.e33 - 1) > FLT_EPSILON) { fabs(m.e31) > FLT_EPSILON || fabs(m.e32) > FLT_EPSILON || fabs(m.e33 - 1) > FLT_EPSILON) {
paintDataByteCnt += writeMember(TVG_TAG_PAINT_TRANSFORM, sizeof(m), &m); cnt += writeTagProperty(TVG_TAG_PAINT_TRANSFORM, sizeof(m), &m);
} }
//composite
const Paint* cmpTarget = nullptr; const Paint* cmpTarget = nullptr;
auto cmpMethod = paint->composite(&cmpTarget); auto cmpMethod = paint->composite(&cmpTarget);
if (cmpMethod != CompositeMethod::None && cmpTarget) { if (cmpMethod != CompositeMethod::None && cmpTarget) {
paintDataByteCnt += serializeComposite(cmpTarget, cmpMethod); cnt += serializeComposite(cmpTarget, cmpMethod);
} }
return paintDataByteCnt; return cnt;
} }
TvgBinCounter serialize(const Scene* scene) TvgBinCounter serializeScene(const Scene* scene)
{ {
writeMemberIndicator(TVG_TAG_CLASS_SCENE); writeTag(TVG_TAG_CLASS_SCENE);
skipInBufferMemberDataSize(); reserveCount();
auto sceneDataByteCnt = serializeChildren(scene); auto cnt = serializeChildren(scene) + serializePaint(scene);
sceneDataByteCnt += serializePaint(scene);
writeMemberDataSizeAt(sceneDataByteCnt); writeReservedCount(cnt);
return SIZE(TvgBinTag) + SIZE(TvgBinCounter) + sceneDataByteCnt; return SERIAL_DONE(cnt);
} }
TvgBinCounter serializeShapeFill(const Fill* f, TvgBinTag fillTvgBinFlag) TvgBinCounter serializeFill(const Fill* fill, TvgBinTag tag)
{ {
TvgBinCounter fillDataByteCnt = 0;
const Fill::ColorStop* stops = nullptr; const Fill::ColorStop* stops = nullptr;
auto stopsCnt = f->colorStops(&stops); auto stopsCnt = fill->colorStops(&stops);
if (!stops || stopsCnt == 0) return 0; if (!stops || stopsCnt == 0) return 0;
writeMemberIndicator(fillTvgBinFlag); writeTag(tag);
skipInBufferMemberDataSize(); reserveCount();
if (f->id() == TVG_CLASS_ID_RADIAL) { TvgBinCounter cnt = 0;
float argRadial[3];
auto radGrad = static_cast<const RadialGradient*>(f); //radial fill
radGrad->radial(argRadial, argRadial + 1,argRadial + 2); if (fill->id() == TVG_CLASS_ID_RADIAL) {
fillDataByteCnt += writeMember(TVG_TAG_FILL_RADIAL_GRADIENT, sizeof(argRadial), argRadial); float args[3];
} static_cast<const RadialGradient*>(fill)->radial(args, args + 1,args + 2);
else { cnt += writeTagProperty(TVG_TAG_FILL_RADIAL_GRADIENT, sizeof(args), args);
float argLinear[4]; //linear fill
auto linGrad = static_cast<const LinearGradient*>(f); } else {
linGrad->linear(argLinear, argLinear + 1, argLinear + 2, argLinear + 3); float args[4];
fillDataByteCnt += writeMember(TVG_TAG_FILL_LINEAR_GRADIENT, sizeof(argLinear), argLinear); static_cast<const LinearGradient*>(fill)->linear(args, args + 1, args + 2, args + 3);
cnt += writeTagProperty(TVG_TAG_FILL_LINEAR_GRADIENT, sizeof(args), args);
} }
auto flag = static_cast<TvgBinFlag>(f->spread()); auto flag = static_cast<TvgBinFlag>(fill->spread());
fillDataByteCnt += writeMember(TVG_TAG_FILL_FILLSPREAD, SIZE(TvgBinFlag), &flag); cnt += writeTagProperty(TVG_TAG_FILL_FILLSPREAD, SIZE(TvgBinFlag), &flag);
fillDataByteCnt += writeMember(TVG_TAG_FILL_COLORSTOPS, stopsCnt * sizeof(stops), stops); cnt += writeTagProperty(TVG_TAG_FILL_COLORSTOPS, stopsCnt * sizeof(stops), stops);
writeMemberDataSizeAt(fillDataByteCnt); writeReservedCount(cnt);
return SIZE(TvgBinTag) + SIZE(TvgBinCounter) + fillDataByteCnt; return SERIAL_DONE(cnt);
} }
TvgBinCounter serializeShapeStroke(const Shape* shape) TvgBinCounter serializeStroke(const Shape* shape)
{ {
TvgBinCounter strokeDataByteCnt = 0; writeTag(TVG_TAG_SHAPE_STROKE);
TvgBinFlag flag; reserveCount();
writeMemberIndicator(TVG_TAG_SHAPE_STROKE); //cap
skipInBufferMemberDataSize(); auto flag = static_cast<TvgBinFlag>(shape->strokeCap());
auto cnt = writeTagProperty(TVG_TAG_SHAPE_STROKE_CAP, SIZE(TvgBinFlag), &flag);
flag = static_cast<TvgBinFlag>(shape->strokeCap());
strokeDataByteCnt += writeMember(TVG_TAG_SHAPE_STROKE_CAP, SIZE(TvgBinFlag), &flag);
//join
flag = static_cast<TvgBinFlag>(shape->strokeJoin()); flag = static_cast<TvgBinFlag>(shape->strokeJoin());
strokeDataByteCnt += writeMember(TVG_TAG_SHAPE_STROKE_JOIN, SIZE(TvgBinFlag), &flag); cnt += writeTagProperty(TVG_TAG_SHAPE_STROKE_JOIN, SIZE(TvgBinFlag), &flag);
float width = shape->strokeWidth(); //width
strokeDataByteCnt += writeMember(TVG_TAG_SHAPE_STROKE_WIDTH, sizeof(width), &width); auto width = shape->strokeWidth();
cnt += writeTagProperty(TVG_TAG_SHAPE_STROKE_WIDTH, sizeof(width), &width);
//fill
if (auto fill = shape->strokeFill()) { if (auto fill = shape->strokeFill()) {
strokeDataByteCnt += serializeShapeFill(fill, TVG_TAG_SHAPE_STROKE_FILL); cnt += serializeFill(fill, TVG_TAG_SHAPE_STROKE_FILL);
} else { } else {
uint8_t color[4] = {0, 0, 0, 0}; uint8_t color[4] = {0, 0, 0, 0};
shape->strokeColor(color, color + 1, color + 2, color + 3); shape->strokeColor(color, color + 1, color + 2, color + 3);
strokeDataByteCnt += writeMember(TVG_TAG_SHAPE_STROKE_COLOR, sizeof(color), &color); cnt += writeTagProperty(TVG_TAG_SHAPE_STROKE_COLOR, sizeof(color), &color);
} }
//dash
const float* dashPattern = nullptr; const float* dashPattern = nullptr;
uint32_t dashCnt = shape->strokeDash(&dashPattern); auto dashCnt = shape->strokeDash(&dashPattern);
if (dashPattern && dashCnt > 0) { if (dashPattern && dashCnt > 0) {
TvgBinCounter dashCntByteCnt = sizeof(dashCnt); TvgBinCounter dashCntSize = sizeof(dashCnt);
TvgBinCounter dashPtrnByteCnt = dashCnt * sizeof(dashPattern[0]); TvgBinCounter dashPtrnSize = dashCnt * sizeof(dashPattern[0]);
writeMemberIndicator(TVG_TAG_SHAPE_STROKE_DASHPTRN); writeTag(TVG_TAG_SHAPE_STROKE_DASHPTRN);
writeMemberDataSize(dashCntByteCnt + dashPtrnByteCnt); writeCount(dashCntSize + dashPtrnSize);
strokeDataByteCnt += writeMemberData(&dashCnt, dashCntByteCnt); cnt += writeData(&dashCnt, dashCntSize);
strokeDataByteCnt += writeMemberData(dashPattern, dashPtrnByteCnt); cnt += writeData(dashPattern, dashPtrnSize);
strokeDataByteCnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter); cnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter);
} }
writeMemberDataSizeAt(strokeDataByteCnt); writeReservedCount(cnt);
return SIZE(TvgBinTag) + SIZE(TvgBinCounter) + strokeDataByteCnt; return SERIAL_DONE(cnt);
} }
TvgBinCounter serializeShapePath(const Shape* shape) TvgBinCounter serializePath(const Shape* shape)
{ {
const PathCommand* cmds = nullptr; const PathCommand* cmds = nullptr;
uint32_t cmdCnt = shape->pathCommands(&cmds); auto cmdCnt = shape->pathCommands(&cmds);
const Point* pts = nullptr; const Point* pts = nullptr;
uint32_t ptsCnt = shape->pathCoords(&pts); auto ptsCnt = shape->pathCoords(&pts);
if (!cmds || !pts || !cmdCnt || !ptsCnt) return 0; if (!cmds || !pts || cmdCnt == 0 || ptsCnt == 0) return 0;
TvgBinCounter pathDataByteCnt = 0; writeTag(TVG_TAG_SHAPE_PATH);
reserveCount();
writeMemberIndicator(TVG_TAG_SHAPE_PATH); auto cnt = writeData(&cmdCnt, sizeof(cmdCnt));
skipInBufferMemberDataSize(); cnt += writeData(&ptsCnt, sizeof(ptsCnt));
cnt += writeData(cmds, cmdCnt * sizeof(cmds[0]));
cnt += writeData(pts, ptsCnt * sizeof(pts[0]));
pathDataByteCnt += writeMemberData(&cmdCnt, sizeof(cmdCnt)); writeReservedCount(cnt);
pathDataByteCnt += writeMemberData(&ptsCnt, sizeof(ptsCnt));
pathDataByteCnt += writeMemberData(cmds, cmdCnt * sizeof(cmds[0]));
pathDataByteCnt += writeMemberData(pts, ptsCnt * sizeof(pts[0]));
writeMemberDataSizeAt(pathDataByteCnt); return SERIAL_DONE(cnt);
return SIZE(TvgBinTag) + SIZE(TvgBinCounter) + pathDataByteCnt;
} }
TvgBinCounter serialize(const Shape* shape) TvgBinCounter serializeShape(const Shape* shape)
{ {
writeMemberIndicator(TVG_TAG_CLASS_SHAPE); writeTag(TVG_TAG_CLASS_SHAPE);
skipInBufferMemberDataSize(); reserveCount();
auto ruleTvgBinFlag = (shape->fillRule() == FillRule::EvenOdd) ? TVG_FLAG_SHAPE_FILLRULE_EVENODD : TVG_FLAG_SHAPE_FILLRULE_WINDING; //fill rule
auto shapeDataByteCnt = writeMember(TVG_TAG_SHAPE_FILLRULE, SIZE(TvgBinFlag), &ruleTvgBinFlag); auto flag = (shape->fillRule() == FillRule::EvenOdd) ? TVG_FLAG_SHAPE_FILLRULE_EVENODD : TVG_FLAG_SHAPE_FILLRULE_WINDING;
auto cnt = writeTagProperty(TVG_TAG_SHAPE_FILLRULE, SIZE(TvgBinFlag), &flag);
if (shape->strokeWidth() > 0) shapeDataByteCnt += serializeShapeStroke(shape); //stroke
if (shape->strokeWidth() > 0) cnt += serializeStroke(shape);
//fill
if (auto fill = shape->fill()) { if (auto fill = shape->fill()) {
shapeDataByteCnt += serializeShapeFill(fill, TVG_TAG_SHAPE_FILL); cnt += serializeFill(fill, TVG_TAG_SHAPE_FILL);
} else { } else {
uint8_t color[4] = {0, 0, 0, 0}; uint8_t color[4] = {0, 0, 0, 0};
shape->fillColor(color, color + 1, color + 2, color + 3); shape->fillColor(color, color + 1, color + 2, color + 3);
shapeDataByteCnt += writeMember(TVG_TAG_SHAPE_COLOR, sizeof(color), color); cnt += writeTagProperty(TVG_TAG_SHAPE_COLOR, sizeof(color), color);
} }
shapeDataByteCnt += serializeShapePath(shape); cnt += serializePath(shape);
shapeDataByteCnt += serializePaint(shape); cnt += serializePaint(shape);
writeMemberDataSizeAt(shapeDataByteCnt); writeReservedCount(cnt);
return SIZE(TvgBinTag) + SIZE(TvgBinCounter) + shapeDataByteCnt; return SERIAL_DONE(cnt);
} }
TvgBinCounter serialize(const Picture* picture) TvgBinCounter serializePicture(const Picture* picture)
{ {
auto pixels = picture->data(); writeTag(TVG_TAG_CLASS_PICTURE);
reserveCount();
TvgBinCounter pictureDataByteCnt = 0; TvgBinCounter cnt = 0;
writeMemberIndicator(TVG_TAG_CLASS_PICTURE); //Bitmap Image
skipInBufferMemberDataSize(); if (auto pixels = picture->data()) {
//TODO: Loader expects uints
float fw, fh;
picture->size(&fw, &fh);
if (pixels) { auto w = static_cast<uint32_t>(fw);
//TODO - loader expects uints auto h = static_cast<uint32_t>(fh);
float vw, vh; TvgBinCounter sizeCnt = sizeof(w);
picture->viewbox(nullptr, nullptr, &vw, &vh); TvgBinCounter imgSize = w * h * sizeof(pixels[0]);
uint32_t w = static_cast<uint32_t>(vw); writeTag(TVG_TAG_PICTURE_RAW_IMAGE);
uint32_t h = static_cast<uint32_t>(vh); writeCount(2 * sizeCnt + imgSize);
TvgBinCounter wByteCnt = sizeof(w); // same as h size
TvgBinCounter pixelsByteCnt = w * h * sizeof(pixels[0]);
writeMemberIndicator(TVG_TAG_PICTURE_RAW_IMAGE); cnt += writeData(&w, sizeCnt);
writeMemberDataSize(2 * wByteCnt + pixelsByteCnt); cnt += writeData(&h, sizeCnt);
pictureDataByteCnt += writeMemberData(&w, wByteCnt); cnt += writeData(pixels, imgSize);
pictureDataByteCnt += writeMemberData(&h, wByteCnt); cnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter);
pictureDataByteCnt += writeMemberData(pixels, pixelsByteCnt); //Vector Image
pictureDataByteCnt += SIZE(TvgBinTag) + SIZE(TvgBinCounter);
} else { } else {
pictureDataByteCnt += serializeChildren(picture); cnt += serializeChildren(picture);
} }
pictureDataByteCnt += serializePaint(picture); cnt += serializePaint(picture);
writeMemberDataSizeAt(pictureDataByteCnt); writeReservedCount(cnt);
return SIZE(TvgBinTag) + SIZE(TvgBinCounter) + pictureDataByteCnt; return SERIAL_DONE(cnt);
} }
TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod) TvgBinCounter serializeComposite(const Paint* cmpTarget, CompositeMethod cmpMethod)
{ {
TvgBinCounter cmpDataByteCnt = 0; writeTag(TVG_TAG_PAINT_CMP_TARGET);
reserveCount();
writeMemberIndicator(TVG_TAG_PAINT_CMP_TARGET); auto flag = static_cast<TvgBinFlag>(cmpMethod);
skipInBufferMemberDataSize(); auto cnt = writeTagProperty(TVG_TAG_PAINT_CMP_METHOD, SIZE(TvgBinFlag), &flag);
auto cmpMethodTvgBinFlag = static_cast<TvgBinFlag>(cmpMethod); cnt += serialize(cmpTarget);
cmpDataByteCnt += writeMember(TVG_TAG_PAINT_CMP_METHOD, SIZE(TvgBinFlag), &cmpMethodTvgBinFlag);
cmpDataByteCnt += serialize(cmpTarget); writeReservedCount(cnt);
writeMemberDataSizeAt(cmpDataByteCnt); return SERIAL_DONE(cnt);
return SIZE(TvgBinTag) + SIZE(TvgBinCounter) + cmpDataByteCnt;
} }
TvgBinCounter serializeChildren(const Paint* paint) TvgBinCounter serializeChildren(const Paint* paint)
{ {
TvgBinCounter dataByteCnt = 0;
auto it = paint->pImpl->iterator(); auto it = paint->pImpl->iterator();
if (!it) return 0;
while (auto p = it->next()) { TvgBinCounter cnt = 0;
dataByteCnt += serialize(p);
} while (auto p = it->next())
cnt += serialize(p);
delete(it); delete(it);
return dataByteCnt; return cnt;
} }
TvgBinCounter serialize(const Paint* paint) TvgBinCounter serialize(const Paint* paint)
@ -367,9 +381,9 @@ struct Saver::Impl
if (!paint) return 0; if (!paint) return 0;
switch (paint->id()) { switch (paint->id()) {
case TVG_CLASS_ID_SHAPE: return serialize(static_cast<const Shape*>(paint)); case TVG_CLASS_ID_SHAPE: return serializeShape(static_cast<const Shape*>(paint));
case TVG_CLASS_ID_SCENE: return serialize(static_cast<const Scene*>(paint)); case TVG_CLASS_ID_SCENE: return serializeScene(static_cast<const Scene*>(paint));
case TVG_CLASS_ID_PICTURE: return serialize(static_cast<const Picture*>(paint)); case TVG_CLASS_ID_PICTURE: return serializePicture(static_cast<const Picture*>(paint));
} }
return 0; return 0;
@ -386,7 +400,7 @@ struct Saver::Impl
if (!writeHeader()) return false; if (!writeHeader()) return false;
if (serialize(paint) == 0) return false; if (serialize(paint) == 0) return false;
if (!bufferToFile(path)) return false; if (!flushTo(path)) return false;
return true; return true;
} }