mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-10-09 00:05:23 +00:00
初始化
This commit is contained in:
@@ -0,0 +1,917 @@
|
||||
#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
|
Reference in New Issue
Block a user