cocos-enhance-kit/cocos2d-x/cocos/platform/win32/CCCanvasRenderingContext2D-win32.cpp
2022-06-25 00:23:03 +08:00

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