mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-01-14 15:01:07 +00:00
918 lines
26 KiB
C++
918 lines
26 KiB
C++
#include "platform/CCCanvasRenderingContext2D.h"
|
|
#include "base/ccTypes.h"
|
|
#include "base/csscolorparser.hpp"
|
|
|
|
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
|
|
#include "cocos/scripting/js-bindings/manual/jsb_platform.h"
|
|
|
|
#include "platform/CCFileUtils.h"
|
|
#include <regex>
|
|
|
|
using namespace cocos2d;
|
|
|
|
enum class CanvasTextAlign {
|
|
LEFT,
|
|
CENTER,
|
|
RIGHT
|
|
};
|
|
|
|
enum class CanvasTextBaseline {
|
|
TOP,
|
|
MIDDLE,
|
|
BOTTOM
|
|
};
|
|
|
|
namespace {
|
|
void fillRectWithColor(uint8_t* buf, uint32_t totalWidth, uint32_t totalHeight, uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
|
|
{
|
|
assert(x + width <= totalWidth);
|
|
assert(y + height <= totalHeight);
|
|
|
|
uint32_t y0 = y;
|
|
uint32_t y1 = y + height;
|
|
uint8_t* p;
|
|
for (uint32_t offsetY = y0; offsetY < y1; ++offsetY)
|
|
{
|
|
for (uint32_t offsetX = x; offsetX < (x + width); ++offsetX)
|
|
{
|
|
p = buf + (totalWidth * offsetY + offsetX) * 4;
|
|
*p++ = r;
|
|
*p++ = g;
|
|
*p++ = b;
|
|
*p++ = a;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class CanvasRenderingContext2DImpl
|
|
{
|
|
public:
|
|
CanvasRenderingContext2DImpl() : _DC(nullptr)
|
|
, _bmp(nullptr)
|
|
, _font((HFONT)GetStockObject(DEFAULT_GUI_FONT))
|
|
, _wnd(nullptr)
|
|
, _savedDC(0)
|
|
{
|
|
_wnd = nullptr;
|
|
HDC hdc = GetDC(_wnd);
|
|
_DC = CreateCompatibleDC(hdc);
|
|
ReleaseDC(_wnd, hdc);
|
|
}
|
|
|
|
~CanvasRenderingContext2DImpl()
|
|
{
|
|
_deleteBitmap();
|
|
_removeCustomFont();
|
|
if (_DC)
|
|
DeleteDC(_DC);
|
|
}
|
|
|
|
void recreateBuffer(float w, float h)
|
|
{
|
|
_bufferWidth = w;
|
|
_bufferHeight = h;
|
|
if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
|
{
|
|
_deleteBitmap();
|
|
return;
|
|
}
|
|
|
|
int textureSize = _bufferWidth * _bufferHeight * 4;
|
|
uint8_t* data = (uint8_t*)malloc(sizeof(uint8_t) * textureSize);
|
|
memset(data, 0x00, textureSize);
|
|
_imageData.fastSet(data, textureSize);
|
|
|
|
_prepareBitmap(_bufferWidth, _bufferHeight);
|
|
}
|
|
|
|
void beginPath()
|
|
{
|
|
// called: set_lineWidth() -> beginPath() -> moveTo() -> lineTo() -> stroke(), when draw line
|
|
_hpen = CreatePen(PS_SOLID, _lineWidth, RGB(255, 255, 255));
|
|
// the return value of SelectObject is a handle to the object being replaced, so we should delete them to avoid memory leak
|
|
HGDIOBJ hOldPen = SelectObject(_DC, _hpen);
|
|
HGDIOBJ hOldBmp = SelectObject(_DC, _bmp);
|
|
DeleteObject(hOldPen);
|
|
DeleteObject(hOldBmp);
|
|
|
|
SetBkMode(_DC, TRANSPARENT);
|
|
}
|
|
|
|
void closePath()
|
|
{
|
|
}
|
|
|
|
void moveTo(float x, float y)
|
|
{
|
|
MoveToEx(_DC, x, -(y - _bufferHeight - _fontSize), nullptr);
|
|
}
|
|
|
|
void lineTo(float x, float y)
|
|
{
|
|
LineTo(_DC, x, -(y - _bufferHeight - _fontSize));
|
|
}
|
|
|
|
void stroke()
|
|
{
|
|
DeleteObject(_hpen);
|
|
if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
|
return;
|
|
_fillTextureData();
|
|
}
|
|
|
|
void saveContext()
|
|
{
|
|
_savedDC = SaveDC(_DC);
|
|
}
|
|
|
|
void restoreContext()
|
|
{
|
|
BOOL ret = RestoreDC(_DC, _savedDC);
|
|
if (0 == ret)
|
|
{
|
|
SE_LOGD("CanvasRenderingContext2DImpl restore context failed.\n");
|
|
}
|
|
}
|
|
|
|
void clearRect(float x, float y, float w, float h)
|
|
{
|
|
if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
|
return;
|
|
if (_imageData.isNull())
|
|
return;
|
|
|
|
recreateBuffer(w, h);
|
|
}
|
|
|
|
void fillRect(float x, float y, float w, float h)
|
|
{
|
|
if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
|
return;
|
|
|
|
//not filled all Bits in buffer? the buffer length is _bufferWidth * _bufferHeight * 4, but it filled _bufferWidth * _bufferHeight * 3?
|
|
uint8_t* buffer = _imageData.getBytes();
|
|
if (buffer)
|
|
{
|
|
uint8_t r = _fillStyle.r * 255.0f;
|
|
uint8_t g = _fillStyle.g * 255.0f;
|
|
uint8_t b = _fillStyle.b * 255.0f;
|
|
uint8_t a = _fillStyle.a * 255.0f;
|
|
fillRectWithColor(buffer, (uint32_t)_bufferWidth, (uint32_t)_bufferHeight, (uint32_t)x, (uint32_t)y, (uint32_t)w, (uint32_t)h, r, g, b, a);
|
|
}
|
|
}
|
|
|
|
void fillText(const std::string& text, float x, float y, float maxWidth)
|
|
{
|
|
if (text.empty() || _bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
|
return;
|
|
|
|
SIZE textSize = { 0, 0 };
|
|
Point offsetPoint = _convertDrawPoint(Point(x, y), text);
|
|
|
|
_drawText(text, (int)offsetPoint.x, (int)offsetPoint.y);
|
|
_fillTextureData();
|
|
|
|
}
|
|
|
|
void strokeText(const std::string& text, float x, float y, float maxWidth)
|
|
{
|
|
if (text.empty() || _bufferWidth < 1.0f || _bufferHeight < 1.0f)
|
|
return;
|
|
// REFINE
|
|
}
|
|
|
|
cocos2d::Size measureText(const std::string& text)
|
|
{
|
|
if (text.empty())
|
|
return Size(0.0f, 0.0f);
|
|
|
|
int bufferLen = 0;
|
|
wchar_t * pwszBuffer = _utf8ToUtf16(text, &bufferLen);
|
|
SIZE size = _sizeWithText(pwszBuffer, bufferLen);
|
|
//SE_LOGD("CanvasRenderingContext2DImpl::measureText: %s, %d, %d\n", text.c_str(), size.cx, size.cy);
|
|
CC_SAFE_DELETE_ARRAY(pwszBuffer);
|
|
return Size(size.cx, size.cy);
|
|
}
|
|
|
|
void updateFont(const std::string& fontName, float fontSize, bool bold = false)
|
|
{
|
|
do
|
|
{
|
|
_fontName = fontName;
|
|
_fontSize = fontSize;
|
|
std::string fontPath;
|
|
LOGFONTA tFont = { 0 };
|
|
if (!_fontName.empty())
|
|
{
|
|
// firstly, try to create font from ttf file
|
|
const auto& fontInfoMap = getFontFamilyNameMap();
|
|
auto iter = fontInfoMap.find(_fontName);
|
|
if (iter != fontInfoMap.end())
|
|
{
|
|
fontPath = iter->second;
|
|
std::string tmpFontPath = fontPath;
|
|
int nFindPos = tmpFontPath.rfind("/");
|
|
tmpFontPath = &tmpFontPath[nFindPos + 1];
|
|
nFindPos = tmpFontPath.rfind(".");
|
|
// IDEA: draw ttf failed if font file name not equal font face name
|
|
// for example: "DejaVuSansMono-Oblique" not equal "DejaVu Sans Mono" when using DejaVuSansMono-Oblique.ttf
|
|
_fontName = tmpFontPath.substr(0, nFindPos);
|
|
}
|
|
else
|
|
{
|
|
auto nFindPos = fontName.rfind("/");
|
|
if (nFindPos != fontName.npos)
|
|
{
|
|
if (fontName.length() == nFindPos + 1)
|
|
{
|
|
_fontName = "";
|
|
}
|
|
else
|
|
{
|
|
_fontName = &_fontName[nFindPos + 1];
|
|
}
|
|
}
|
|
}
|
|
tFont.lfCharSet = DEFAULT_CHARSET;
|
|
strcpy_s(tFont.lfFaceName, LF_FACESIZE, _fontName.c_str());
|
|
}
|
|
|
|
if (_fontSize)
|
|
tFont.lfHeight = -_fontSize;
|
|
|
|
if (bold)
|
|
tFont.lfWeight = FW_BOLD;
|
|
else
|
|
tFont.lfWeight = FW_NORMAL;
|
|
|
|
// disable Cleartype
|
|
tFont.lfQuality = ANTIALIASED_QUALITY;
|
|
|
|
// delete old font
|
|
_removeCustomFont();
|
|
|
|
if (fontPath.size() > 0)
|
|
{
|
|
_curFontPath = fontPath;
|
|
wchar_t * pwszBuffer = _utf8ToUtf16(_curFontPath);
|
|
if (pwszBuffer)
|
|
{
|
|
if (AddFontResource(pwszBuffer))
|
|
{
|
|
SendMessage(_wnd, WM_FONTCHANGE, 0, 0);
|
|
}
|
|
delete[] pwszBuffer;
|
|
pwszBuffer = nullptr;
|
|
}
|
|
}
|
|
|
|
// create new font
|
|
_font = CreateFontIndirectA(&tFont);
|
|
if (!_font)
|
|
{
|
|
// create failed, use default font
|
|
SE_LOGE("Failed to create custom font(font name: %s, font size: %f), use default font.\n",
|
|
_fontName.c_str(), fontSize);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
SelectObject(_DC, _font);
|
|
SendMessage(_wnd, WM_FONTCHANGE, 0, 0);
|
|
}
|
|
} while (0);
|
|
}
|
|
|
|
void setTextAlign(CanvasTextAlign align)
|
|
{
|
|
_textAlign = align;
|
|
}
|
|
|
|
void setTextBaseline(CanvasTextBaseline baseline)
|
|
{
|
|
_textBaseLine = baseline;
|
|
}
|
|
|
|
void setFillStyle(float r, float g, float b, float a)
|
|
{
|
|
_fillStyle.r = r;
|
|
_fillStyle.g = g;
|
|
_fillStyle.b = b;
|
|
_fillStyle.a = a;
|
|
}
|
|
|
|
void setStrokeStyle(float r, float g, float b, float a)
|
|
{
|
|
_strokeStyle.r = r;
|
|
_strokeStyle.g = g;
|
|
_strokeStyle.b = b;
|
|
_strokeStyle.a = a;
|
|
}
|
|
|
|
void setLineWidth(float lineWidth)
|
|
{
|
|
_lineWidth = lineWidth;
|
|
}
|
|
|
|
void setPremultiply(bool multiply)
|
|
{
|
|
_premultiply = multiply;
|
|
}
|
|
|
|
const Data& getDataRef() const
|
|
{
|
|
return _imageData;
|
|
}
|
|
|
|
HDC _DC;
|
|
HBITMAP _bmp;
|
|
private:
|
|
|
|
Data _imageData;
|
|
HFONT _font;
|
|
HWND _wnd;
|
|
HPEN _hpen;
|
|
PAINTSTRUCT _paintStruct;
|
|
std::string _curFontPath;
|
|
int _savedDC;
|
|
float _lineWidth = 0.0f;
|
|
float _bufferWidth = 0.0f;
|
|
float _bufferHeight = 0.0f;
|
|
bool _premultiply = true;
|
|
|
|
std::string _fontName;
|
|
int _fontSize;
|
|
SIZE _textSize;
|
|
CanvasTextAlign _textAlign;
|
|
CanvasTextBaseline _textBaseLine;
|
|
cocos2d::Color4F _fillStyle;
|
|
cocos2d::Color4F _strokeStyle;
|
|
|
|
TEXTMETRIC _tm;
|
|
|
|
// change utf-8 string to utf-16, pRetLen is the string length after changing
|
|
wchar_t * _utf8ToUtf16(const std::string& str, int * pRetLen = nullptr)
|
|
{
|
|
wchar_t * pwszBuffer = nullptr;
|
|
do
|
|
{
|
|
if (str.empty())
|
|
{
|
|
break;
|
|
}
|
|
int nLen = str.size();
|
|
int nBufLen = nLen + 1;
|
|
pwszBuffer = new wchar_t[nBufLen];
|
|
CC_BREAK_IF(!pwszBuffer);
|
|
memset(pwszBuffer, 0, sizeof(wchar_t) * nBufLen);
|
|
// str.size() not equal actuallyLen for Chinese char
|
|
int actuallyLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), nLen, pwszBuffer, nBufLen);
|
|
// SE_LOGE("_utf8ToUtf16, str:%s, strLen:%d, retLen:%d\n", str.c_str(), str.size(), actuallyLen);
|
|
if (pRetLen != nullptr) {
|
|
*pRetLen = actuallyLen;
|
|
}
|
|
} while (0);
|
|
return pwszBuffer;
|
|
|
|
}
|
|
|
|
void _removeCustomFont()
|
|
{
|
|
HFONT hDefFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
|
|
if (hDefFont != _font)
|
|
{
|
|
DeleteObject(SelectObject(_DC, hDefFont));
|
|
}
|
|
// release temp font resource
|
|
if (_curFontPath.size() > 0)
|
|
{
|
|
wchar_t * pwszBuffer = _utf8ToUtf16(_curFontPath);
|
|
if (pwszBuffer)
|
|
{
|
|
RemoveFontResource(pwszBuffer);
|
|
SendMessage(_wnd, WM_FONTCHANGE, 0, 0);
|
|
delete[] pwszBuffer;
|
|
pwszBuffer = nullptr;
|
|
}
|
|
_curFontPath.clear();
|
|
}
|
|
}
|
|
|
|
// x, y offset value
|
|
int _drawText(const std::string& text, int x, int y)
|
|
{
|
|
int nRet = 0;
|
|
wchar_t * pwszBuffer = nullptr;
|
|
do
|
|
{
|
|
CC_BREAK_IF(text.empty());
|
|
|
|
DWORD dwFmt = DT_SINGLELINE | DT_NOPREFIX;
|
|
|
|
int bufferLen = 0;
|
|
pwszBuffer = _utf8ToUtf16(text, &bufferLen);
|
|
|
|
SIZE newSize = _sizeWithText(pwszBuffer, bufferLen);
|
|
|
|
_textSize = newSize;
|
|
|
|
RECT rcText = { 0 };
|
|
|
|
rcText.right = newSize.cx;
|
|
rcText.bottom = newSize.cy;
|
|
|
|
LONG offsetX = x;
|
|
LONG offsetY = y;
|
|
if (offsetX || offsetY)
|
|
{
|
|
OffsetRect(&rcText, offsetX, offsetY);
|
|
}
|
|
|
|
// SE_LOGE("_drawText text,%s size: (%d, %d) offset after convert: (%d, %d) \n", text.c_str(), newSize.cx, newSize.cy, offsetX, offsetY);
|
|
|
|
SetBkMode(_DC, TRANSPARENT);
|
|
SetTextColor(_DC, RGB(255, 255, 255)); // white color
|
|
|
|
// draw text
|
|
nRet = DrawTextW(_DC, pwszBuffer, bufferLen, &rcText, dwFmt);
|
|
} while (0);
|
|
CC_SAFE_DELETE_ARRAY(pwszBuffer);
|
|
|
|
return nRet;
|
|
}
|
|
|
|
SIZE _sizeWithText(const wchar_t * pszText, int nLen)
|
|
{
|
|
SIZE tRet = { 0 };
|
|
do
|
|
{
|
|
CC_BREAK_IF(!pszText || nLen <= 0);
|
|
|
|
RECT rc = { 0, 0, 0, 0 };
|
|
DWORD dwCalcFmt = DT_CALCRECT | DT_NOPREFIX;
|
|
|
|
// measure text size
|
|
DrawTextW(_DC, pszText, nLen, &rc, dwCalcFmt);
|
|
|
|
tRet.cx = rc.right;
|
|
tRet.cy = rc.bottom;
|
|
} while (0);
|
|
|
|
return tRet;
|
|
}
|
|
|
|
void _prepareBitmap(int nWidth, int nHeight)
|
|
{
|
|
// release bitmap
|
|
_deleteBitmap();
|
|
|
|
if (nWidth > 0 && nHeight > 0)
|
|
{
|
|
_bmp = CreateBitmap(nWidth, nHeight, 1, 32, nullptr);
|
|
SelectObject(_DC, _bmp);
|
|
}
|
|
}
|
|
|
|
void _deleteBitmap()
|
|
{
|
|
if (_bmp)
|
|
{
|
|
DeleteObject(_bmp);
|
|
_bmp = nullptr;
|
|
}
|
|
}
|
|
|
|
void _fillTextureData()
|
|
{
|
|
do
|
|
{
|
|
int dataLen = _bufferWidth * _bufferHeight * 4;
|
|
unsigned char* dataBuf = (unsigned char*)malloc(sizeof(unsigned char) * dataLen);
|
|
CC_BREAK_IF(!dataBuf);
|
|
unsigned char* imageBuf = _imageData.getBytes();
|
|
CC_BREAK_IF(!imageBuf);
|
|
|
|
struct
|
|
{
|
|
BITMAPINFOHEADER bmiHeader;
|
|
int mask[4];
|
|
} bi = { 0 };
|
|
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
|
|
CC_BREAK_IF(!GetDIBits(_DC, _bmp, 0, 0,
|
|
nullptr, (LPBITMAPINFO)&bi, DIB_RGB_COLORS));
|
|
|
|
// copy pixel data
|
|
bi.bmiHeader.biHeight = (bi.bmiHeader.biHeight > 0) ? -bi.bmiHeader.biHeight : bi.bmiHeader.biHeight;
|
|
GetDIBits(_DC, _bmp, 0, _bufferHeight, dataBuf,
|
|
(LPBITMAPINFO)&bi, DIB_RGB_COLORS);
|
|
|
|
|
|
uint8_t r = _fillStyle.r * 255;
|
|
uint8_t g = _fillStyle.g * 255;
|
|
uint8_t b = _fillStyle.b * 255;
|
|
uint8_t a = _fillStyle.a;
|
|
COLORREF textColor = (b << 16 | g << 8 | r) & 0x00ffffff;
|
|
COLORREF * pPixel = nullptr;
|
|
COLORREF * pImage = nullptr;
|
|
|
|
if (_premultiply)
|
|
{
|
|
uint8_t dirtyValue = 0;
|
|
for (int y = 0; y < _bufferHeight; ++y)
|
|
{
|
|
pPixel = (COLORREF *)dataBuf + y * (int)_bufferWidth;
|
|
pImage = (COLORREF *)imageBuf + y * (int)_bufferWidth;
|
|
for (int x = 0; x < _bufferWidth; ++x)
|
|
{
|
|
COLORREF& clr = *pPixel;
|
|
COLORREF& val = *pImage;
|
|
dirtyValue = GetRValue(clr);
|
|
// "dirtyValue > 0" means pixel was covered when drawing text
|
|
if (dirtyValue > 0)
|
|
{
|
|
// r = _fillStyle.r * 255 * (dirtyValue / 255) * alpha;
|
|
r = _fillStyle.r * dirtyValue * a;
|
|
g = _fillStyle.g * dirtyValue * a;
|
|
b = _fillStyle.b * dirtyValue * a;
|
|
textColor = (b << 16 | g << 8 | r) & 0x00ffffff;
|
|
val = ((BYTE)(dirtyValue * a) << 24) | textColor;
|
|
}
|
|
++pPixel;
|
|
++pImage;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int y = 0; y < _bufferHeight; ++y)
|
|
{
|
|
pPixel = (COLORREF *)dataBuf + y * (int)_bufferWidth;
|
|
pImage = (COLORREF *)imageBuf + y * (int)_bufferWidth;
|
|
for (int x = 0; x < _bufferWidth; ++x)
|
|
{
|
|
COLORREF& clr = *pPixel;
|
|
COLORREF& val = *pImage;
|
|
// Because text is drawn in white color, and background color is black,
|
|
// so the red value is equal to alpha value. And we should keep this value
|
|
// as it includes anti-atlas information.
|
|
uint8_t alpha = GetRValue(clr);
|
|
|
|
if (alpha > 0)
|
|
{
|
|
val = (alpha << 24) | textColor;
|
|
}
|
|
|
|
++pPixel;
|
|
++pImage;
|
|
}
|
|
}
|
|
}
|
|
|
|
free(dataBuf);
|
|
} while (0);
|
|
}
|
|
|
|
Point _convertDrawPoint(Point point, std::string text) {
|
|
Size textSize = measureText(text);
|
|
if (_textAlign == CanvasTextAlign::CENTER)
|
|
{
|
|
point.x -= textSize.width / 2.0f;
|
|
}
|
|
else if (_textAlign == CanvasTextAlign::RIGHT)
|
|
{
|
|
point.x -= textSize.width;
|
|
}
|
|
|
|
if (_textBaseLine == CanvasTextBaseline::TOP)
|
|
{
|
|
point.y += _fontSize;
|
|
}
|
|
else if (_textBaseLine == CanvasTextBaseline::MIDDLE)
|
|
{
|
|
point.y += _fontSize / 2.0f;
|
|
}
|
|
|
|
// Since the web platform cannot get the baseline of the font, an additive offset is performed for all platforms.
|
|
// That's why we should add baseline back again on other platforms
|
|
GetTextMetrics(_DC, &_tm);
|
|
point.y -= _tm.tmAscent;
|
|
|
|
return point;
|
|
}
|
|
};
|
|
|
|
NS_CC_BEGIN
|
|
|
|
CanvasGradient::CanvasGradient()
|
|
{
|
|
//SE_LOGD("CanvasGradient constructor: %p\n", this);
|
|
}
|
|
|
|
CanvasGradient::~CanvasGradient()
|
|
{
|
|
//SE_LOGD("CanvasGradient destructor: %p\n", this);
|
|
}
|
|
|
|
void CanvasGradient::addColorStop(float offset, const std::string& color)
|
|
{
|
|
//SE_LOGD("CanvasGradient::addColorStop: %p\n", this);
|
|
}
|
|
|
|
// CanvasRenderingContext2D
|
|
|
|
CanvasRenderingContext2D::CanvasRenderingContext2D(float width, float height)
|
|
: __width(width)
|
|
, __height(height)
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D constructor: %p, width: %f, height: %f\n", this, width, height);
|
|
_impl = new CanvasRenderingContext2DImpl();
|
|
recreateBufferIfNeeded();
|
|
}
|
|
|
|
CanvasRenderingContext2D::~CanvasRenderingContext2D()
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D destructor: %p\n", this);
|
|
delete _impl;
|
|
}
|
|
|
|
void CanvasRenderingContext2D::recreateBufferIfNeeded()
|
|
{
|
|
if (_isBufferSizeDirty)
|
|
{
|
|
_isBufferSizeDirty = false;
|
|
//SE_LOGD("Recreate buffer %p, w: %f, h:%f\n", this, __width, __height);
|
|
_impl->recreateBuffer(__width, __height);
|
|
if (_canvasBufferUpdatedCB != nullptr)
|
|
_canvasBufferUpdatedCB(_impl->getDataRef());
|
|
}
|
|
}
|
|
|
|
void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height)
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::clearRect: %p, %f, %f, %f, %f\n", this, x, y, width, height);
|
|
recreateBufferIfNeeded();
|
|
_impl->clearRect(x, y, width, height);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height)
|
|
{
|
|
recreateBufferIfNeeded();
|
|
_impl->fillRect(x, y, width, height);
|
|
|
|
if (_canvasBufferUpdatedCB != nullptr)
|
|
_canvasBufferUpdatedCB(_impl->getDataRef());
|
|
}
|
|
|
|
void CanvasRenderingContext2D::fillText(const std::string& text, float x, float y, float maxWidth)
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::fillText: %s, offset: (%f, %f), %f\n", text.c_str(), x, y, maxWidth);
|
|
if (text.empty())
|
|
return;
|
|
recreateBufferIfNeeded();
|
|
|
|
_impl->fillText(text, x, y, maxWidth);
|
|
if (_canvasBufferUpdatedCB != nullptr)
|
|
_canvasBufferUpdatedCB(_impl->getDataRef());
|
|
}
|
|
|
|
void CanvasRenderingContext2D::strokeText(const std::string& text, float x, float y, float maxWidth)
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::strokeText: %s, %f, %f, %f\n", text.c_str(), x, y, maxWidth);
|
|
if (text.empty())
|
|
return;
|
|
recreateBufferIfNeeded();
|
|
|
|
_impl->strokeText(text, x, y, maxWidth);
|
|
|
|
if (_canvasBufferUpdatedCB != nullptr)
|
|
_canvasBufferUpdatedCB(_impl->getDataRef());
|
|
}
|
|
|
|
cocos2d::Size CanvasRenderingContext2D::measureText(const std::string& text)
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::measureText: %s\n", text.c_str());
|
|
return _impl->measureText(text);
|
|
}
|
|
|
|
CanvasGradient* CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
void CanvasRenderingContext2D::save()
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::save\n");
|
|
_impl->saveContext();
|
|
}
|
|
|
|
void CanvasRenderingContext2D::beginPath()
|
|
{
|
|
//SE_LOGD("\n-----------begin------------------\nCanvasRenderingContext2D::beginPath\n");
|
|
_impl->beginPath();
|
|
}
|
|
|
|
void CanvasRenderingContext2D::closePath()
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::closePath\n");
|
|
_impl->closePath();
|
|
}
|
|
|
|
void CanvasRenderingContext2D::moveTo(float x, float y)
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::moveTo\n");
|
|
_impl->moveTo(x, y);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::lineTo(float x, float y)
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::lineTo\n");
|
|
_impl->lineTo(x, y);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::stroke()
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::stroke\n");
|
|
_impl->stroke();
|
|
|
|
if (_canvasBufferUpdatedCB != nullptr)
|
|
_canvasBufferUpdatedCB(_impl->getDataRef());
|
|
}
|
|
|
|
void CanvasRenderingContext2D::restore()
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::restore\n");
|
|
_impl->restoreContext();
|
|
}
|
|
|
|
void CanvasRenderingContext2D::setCanvasBufferUpdatedCallback(const CanvasBufferUpdatedCallback& cb)
|
|
{
|
|
_canvasBufferUpdatedCB = cb;
|
|
}
|
|
void CanvasRenderingContext2D::setPremultiply(bool multiply)
|
|
{
|
|
_impl->setPremultiply(_premultiply);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::set__width(float width)
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::set__width: %f\n", width);
|
|
__width = width;
|
|
_isBufferSizeDirty = true;
|
|
recreateBufferIfNeeded();
|
|
}
|
|
|
|
void CanvasRenderingContext2D::set__height(float height)
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::set__height: %f\n", height);
|
|
__height = height;
|
|
_isBufferSizeDirty = true;
|
|
recreateBufferIfNeeded();
|
|
}
|
|
|
|
void CanvasRenderingContext2D::set_lineWidth(float lineWidth)
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::set_lineWidth %d\n", lineWidth);
|
|
_lineWidth = lineWidth;
|
|
_impl->setLineWidth(lineWidth);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::set_lineCap(const std::string& lineCap)
|
|
{
|
|
//SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::set_lineJoin(const std::string& lineJoin)
|
|
{
|
|
//SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::fill()
|
|
{
|
|
// SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
|
}
|
|
void CanvasRenderingContext2D::rect(float x, float y, float w, float h)
|
|
{
|
|
// SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::set_font(const std::string& font)
|
|
{
|
|
if (_font != font)
|
|
{
|
|
_font = font;
|
|
|
|
std::string boldStr;
|
|
std::string fontName = "Arial";
|
|
std::string fontSizeStr = "30";
|
|
|
|
// support get font name from `60px American` or `60px "American abc-abc_abc"`
|
|
std::regex re("(bold)?\\s*((\\d+)([\\.]\\d+)?)px\\s+([\\w-]+|\"[\\w -]+\"$)");
|
|
std::match_results<std::string::const_iterator> results;
|
|
if (std::regex_search(_font.cbegin(), _font.cend(), results, re))
|
|
{
|
|
boldStr = results[1].str();
|
|
fontSizeStr = results[2].str();
|
|
fontName = results[5].str();
|
|
}
|
|
|
|
float fontSize = atof(fontSizeStr.c_str());
|
|
//SE_LOGD("CanvasRenderingContext2D::set_font: %s, Size: %f, isBold: %b\n", fontName.c_str(), fontSize, !boldStr.empty());
|
|
_impl->updateFont(fontName, fontSize, !boldStr.empty());
|
|
}
|
|
}
|
|
|
|
void CanvasRenderingContext2D::set_textAlign(const std::string& textAlign)
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::set_textAlign: %s\n", textAlign.c_str());
|
|
if (textAlign == "left")
|
|
{
|
|
_impl->setTextAlign(CanvasTextAlign::LEFT);
|
|
}
|
|
else if (textAlign == "center" || textAlign == "middle")
|
|
{
|
|
_impl->setTextAlign(CanvasTextAlign::CENTER);
|
|
}
|
|
else if (textAlign == "right")
|
|
{
|
|
_impl->setTextAlign(CanvasTextAlign::RIGHT);
|
|
}
|
|
else
|
|
{
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
void CanvasRenderingContext2D::set_textBaseline(const std::string& textBaseline)
|
|
{
|
|
//SE_LOGD("CanvasRenderingContext2D::set_textBaseline: %s\n", textBaseline.c_str());
|
|
if (textBaseline == "top")
|
|
{
|
|
_impl->setTextBaseline(CanvasTextBaseline::TOP);
|
|
}
|
|
else if (textBaseline == "middle")
|
|
{
|
|
_impl->setTextBaseline(CanvasTextBaseline::MIDDLE);
|
|
}
|
|
else if (textBaseline == "bottom" || textBaseline == "alphabetic") //REFINE:, how to deal with alphabetic, currently we handle it as bottom mode.
|
|
{
|
|
_impl->setTextBaseline(CanvasTextBaseline::BOTTOM);
|
|
}
|
|
else
|
|
{
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
void CanvasRenderingContext2D::set_fillStyle(const std::string& fillStyle)
|
|
{
|
|
CSSColorParser::Color color = CSSColorParser::parse(fillStyle);
|
|
_impl->setFillStyle(color.r/255.0f, color.g/255.0f, color.b/255.0f, color.a);
|
|
//SE_LOGD("CanvasRenderingContext2D::set_fillStyle: %s, (%d, %d, %d, %f)\n", fillStyle.c_str(), color.r, color.g, color.b, color.a);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::set_strokeStyle(const std::string& strokeStyle)
|
|
{
|
|
CSSColorParser::Color color = CSSColorParser::parse(strokeStyle);
|
|
_impl->setStrokeStyle(color.r/255.0f, color.g/255.0f, color.b/255.0f, color.a);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::set_globalCompositeOperation(const std::string& globalCompositeOperation)
|
|
{
|
|
//SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::_fillImageData(const Data& imageData, float imageWidth, float imageHeight, float offsetX, float offsetY)
|
|
{
|
|
//SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
|
}
|
|
// transform
|
|
//REFINE:
|
|
|
|
void CanvasRenderingContext2D::translate(float x, float y)
|
|
{
|
|
//SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::scale(float x, float y)
|
|
{
|
|
//SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::rotate(float angle)
|
|
{
|
|
//SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::transform(float a, float b, float c, float d, float e, float f)
|
|
{
|
|
//SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
|
}
|
|
|
|
void CanvasRenderingContext2D::setTransform(float a, float b, float c, float d, float e, float f)
|
|
{
|
|
//SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
|
|
}
|
|
|
|
NS_CC_END
|