CCCanvasRenderingContext2D-android.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. #include "platform/CCCanvasRenderingContext2D.h"
  2. #include "base/ccTypes.h"
  3. #include "base/csscolorparser.hpp"
  4. #include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
  5. #include "platform/android/jni/JniHelper.h"
  6. #include "platform/android/jni/JniImp.h"
  7. #include <regex>
  8. #ifndef JCLS_CANVASIMPL
  9. #define JCLS_CANVASIMPL "org/cocos2dx/lib/CanvasRenderingContext2DImpl"
  10. #endif
  11. using namespace cocos2d;
  12. enum class CanvasTextAlign {
  13. LEFT,
  14. CENTER,
  15. RIGHT
  16. };
  17. enum class CanvasTextBaseline {
  18. TOP,
  19. MIDDLE,
  20. BOTTOM
  21. };
  22. class CanvasRenderingContext2DImpl
  23. {
  24. public:
  25. CanvasRenderingContext2DImpl()
  26. {
  27. jobject obj = JniHelper::newObject(JCLS_CANVASIMPL);
  28. _obj = JniHelper::getEnv()->NewGlobalRef(obj);
  29. JniHelper::getEnv()->DeleteLocalRef(obj);
  30. }
  31. ~CanvasRenderingContext2DImpl()
  32. {
  33. JniHelper::getEnv()->DeleteGlobalRef(_obj);
  34. }
  35. void recreateBuffer(float w, float h)
  36. {
  37. _bufferWidth = w;
  38. _bufferHeight = h;
  39. if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
  40. return;
  41. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "recreateBuffer", w, h);
  42. fillData();
  43. }
  44. void beginPath()
  45. {
  46. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "beginPath");
  47. }
  48. void closePath()
  49. {
  50. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "closePath");
  51. }
  52. void moveTo(float x, float y)
  53. {
  54. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "moveTo", x, y);
  55. }
  56. void lineTo(float x, float y)
  57. {
  58. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "lineTo", x, y);
  59. }
  60. void stroke()
  61. {
  62. if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
  63. return;
  64. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "stroke");
  65. fillData();
  66. }
  67. void fill()
  68. {
  69. if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
  70. return;
  71. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "fill");
  72. fillData();
  73. }
  74. void saveContext()
  75. {
  76. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "saveContext");
  77. }
  78. void restoreContext()
  79. {
  80. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "restoreContext");
  81. }
  82. void rect(float x, float y, float w, float h)
  83. {
  84. if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
  85. return;
  86. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "rect", x, y, w, h);
  87. fillData();
  88. }
  89. void clearRect(float x, float y, float w, float h)
  90. {
  91. if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
  92. return;
  93. if (x >= _bufferWidth || y >= _bufferHeight)
  94. return;
  95. if (x + w > _bufferWidth)
  96. w = _bufferWidth - x;
  97. if (y + h > _bufferHeight)
  98. h = _bufferHeight - y;
  99. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "clearRect", x, y, w, h);
  100. fillData();
  101. }
  102. void fillRect(float x, float y, float w, float h)
  103. {
  104. if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
  105. return;
  106. if (x >= _bufferWidth || y >= _bufferHeight)
  107. return;
  108. if (x + w > _bufferWidth)
  109. w = _bufferWidth - x;
  110. if (y + h > _bufferHeight)
  111. h = _bufferHeight - y;
  112. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "fillRect", x, y, w, h);
  113. fillData();
  114. }
  115. void fillText(const std::string& text, float x, float y, float maxWidth)
  116. {
  117. if (text.empty() || _bufferWidth < 1.0f || _bufferHeight < 1.0f)
  118. return;
  119. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "fillText", text, x, y, maxWidth);
  120. fillData();
  121. }
  122. void strokeText(const std::string& text, float x, float y, float maxWidth)
  123. {
  124. if (text.empty() || _bufferWidth < 1.0f || _bufferHeight < 1.0f)
  125. return;
  126. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "strokeText", text, x, y, maxWidth);
  127. fillData();
  128. }
  129. float measureText(const std::string& text)
  130. {
  131. if (text.empty())
  132. return 0.0f;
  133. return JniHelper::callObjectFloatMethod(_obj, JCLS_CANVASIMPL, "measureText", text);
  134. }
  135. void updateFont(const std::string& fontName, float fontSize, bool bold, bool italic, bool oblique, bool smallCaps)
  136. {
  137. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "updateFont", fontName, fontSize, bold, italic, oblique, smallCaps);
  138. }
  139. void setLineCap(const std::string& lineCap) {
  140. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setLineCap", lineCap);
  141. }
  142. void setLineJoin(const std::string& lineJoin) {
  143. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setLineJoin", lineJoin);
  144. }
  145. void setTextAlign(CanvasTextAlign align)
  146. {
  147. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setTextAlign", (int)align);
  148. }
  149. void setTextBaseline(CanvasTextBaseline baseline)
  150. {
  151. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setTextBaseline", (int)baseline);
  152. }
  153. void setFillStyle(float r, float g, float b, float a)
  154. {
  155. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setFillStyle", r, g, b, a);
  156. }
  157. void setStrokeStyle(float r, float g, float b, float a)
  158. {
  159. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setStrokeStyle", r, g, b, a);
  160. }
  161. void setLineWidth(float lineWidth)
  162. {
  163. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "setLineWidth", lineWidth);
  164. }
  165. void _fillImageData(const Data &imageData, float imageWidth, float imageHeight, float offsetX, float offsetY) {
  166. if (_bufferWidth < 1.0f || _bufferHeight < 1.0f)
  167. return;
  168. jbyteArray arr = JniHelper::getEnv()->NewByteArray(imageData.getSize());
  169. JniHelper::getEnv()->SetByteArrayRegion(arr, 0, imageData.getSize(),
  170. (const jbyte *) imageData.getBytes());
  171. JniHelper::callObjectVoidMethod(_obj, JCLS_CANVASIMPL, "_fillImageData", arr, imageWidth,
  172. imageHeight, offsetX, offsetY);
  173. JniHelper::getEnv()->DeleteLocalRef(arr);
  174. fillData();
  175. }
  176. const Data& getDataRef() const
  177. {
  178. return _data;
  179. }
  180. void setPremultiply(bool multiply)
  181. {
  182. _premultiply = multiply;
  183. }
  184. #define CLAMP(V, HI) std::min( (V), (HI) )
  185. void unMultiplyAlpha(unsigned char* ptr, ssize_t size)
  186. {
  187. // Android source data is not premultiplied alpha when API >= 19
  188. // please refer CanvasRenderingContext2DImpl::recreateBuffer(float w, float h)
  189. // in CanvasRenderingContext2DImpl.java
  190. // if (getAndroidSDKInt() >= 19)
  191. // return;
  192. float alpha;
  193. for (int i = 0; i < size; i += 4)
  194. {
  195. alpha = (float)ptr[i + 3];
  196. if (alpha > 0)
  197. {
  198. ptr[i] = CLAMP((int)((float)ptr[i] / alpha * 255), 255);
  199. ptr[i+1] = CLAMP((int)((float)ptr[i+1] / alpha * 255), 255);
  200. ptr[i+2] = CLAMP((int)((float)ptr[i+2] / alpha * 255), 255);
  201. }
  202. }
  203. }
  204. void fillData()
  205. {
  206. jbyteArray arr = JniHelper::callObjectByteArrayMethod(_obj, JCLS_CANVASIMPL, "getDataRef");
  207. jsize len = JniHelper::getEnv()->GetArrayLength(arr);
  208. jbyte* jbarray = (jbyte *)malloc(len * sizeof(jbyte));
  209. JniHelper::getEnv()->GetByteArrayRegion(arr,0,len,jbarray);
  210. if (!_premultiply)
  211. {
  212. unMultiplyAlpha( (unsigned char*) jbarray, len);
  213. }
  214. _data.fastSet((unsigned char*) jbarray, len); //IDEA: DON'T create new jbarray every time.
  215. JniHelper::getEnv()->DeleteLocalRef(arr);
  216. }
  217. private:
  218. jobject _obj = nullptr;
  219. Data _data;
  220. float _bufferWidth = 0.0f;
  221. float _bufferHeight = 0.0f;
  222. bool _premultiply = true;
  223. };
  224. namespace {
  225. 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)
  226. {
  227. assert(x + width <= totalWidth);
  228. assert(y + height <= totalHeight);
  229. uint32_t y0 = totalHeight - (y + height);
  230. uint32_t y1 = totalHeight - y;
  231. uint8_t* p;
  232. for (uint32_t offsetY = y0; offsetY < y1; ++offsetY)
  233. {
  234. for (uint32_t offsetX = x; offsetX < (x + width); ++offsetX)
  235. {
  236. p = buf + (totalWidth * offsetY + offsetX) * 3;
  237. *p++ = r;
  238. *p++ = g;
  239. *p++ = b;
  240. }
  241. }
  242. }
  243. }
  244. NS_CC_BEGIN
  245. CanvasGradient::CanvasGradient()
  246. {
  247. // SE_LOGD("CanvasGradient constructor: %p\n", this);
  248. }
  249. CanvasGradient::~CanvasGradient()
  250. {
  251. // SE_LOGD("CanvasGradient destructor: %p\n", this);
  252. }
  253. void CanvasGradient::addColorStop(float offset, const std::string& color)
  254. {
  255. // SE_LOGD("CanvasGradient::addColorStop: %p\n", this);
  256. }
  257. // CanvasRenderingContext2D
  258. CanvasRenderingContext2D::CanvasRenderingContext2D(float width, float height)
  259. : __width(width)
  260. , __height(height)
  261. {
  262. // SE_LOGD("CanvasRenderingContext2D constructor: %p, width: %f, height: %f\n", this, width, height);
  263. _impl = new CanvasRenderingContext2DImpl();
  264. recreateBufferIfNeeded();
  265. }
  266. CanvasRenderingContext2D::~CanvasRenderingContext2D()
  267. {
  268. // SE_LOGD("CanvasRenderingContext2D destructor: %p\n", this);
  269. delete _impl;
  270. }
  271. void CanvasRenderingContext2D::recreateBufferIfNeeded()
  272. {
  273. if (_isBufferSizeDirty)
  274. {
  275. _isBufferSizeDirty = false;
  276. // SE_LOGD("Recreate buffer %p, w: %f, h:%f\n", this, __width, __height);
  277. _impl->recreateBuffer(__width, __height);
  278. if (_canvasBufferUpdatedCB != nullptr)
  279. _canvasBufferUpdatedCB(_impl->getDataRef());
  280. }
  281. }
  282. void CanvasRenderingContext2D::rect(float x, float y, float width, float height)
  283. {
  284. // SE_LOGD("CanvasRenderingContext2D::rect: %p, %f, %f, %f, %f\n", this, x, y, width, height);
  285. recreateBufferIfNeeded();
  286. _impl->rect(x, y, width, height);
  287. }
  288. void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height)
  289. {
  290. // SE_LOGD("CanvasRenderingContext2D::clearRect: %p, %f, %f, %f, %f\n", this, x, y, width, height);
  291. recreateBufferIfNeeded();
  292. _impl->clearRect(x, y, width, height);
  293. }
  294. void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height)
  295. {
  296. recreateBufferIfNeeded();
  297. _impl->fillRect(x, y, width, height);
  298. if (_canvasBufferUpdatedCB != nullptr)
  299. _canvasBufferUpdatedCB(_impl->getDataRef());
  300. }
  301. void CanvasRenderingContext2D::fillText(const std::string& text, float x, float y, float maxWidth)
  302. {
  303. // SE_LOGD("CanvasRenderingContext2D::fillText: %s, %f, %f, %f\n", text.c_str(), x, y, maxWidth);
  304. if (text.empty())
  305. return;
  306. recreateBufferIfNeeded();
  307. _impl->fillText(text, x, y, maxWidth);
  308. if (_canvasBufferUpdatedCB != nullptr)
  309. _canvasBufferUpdatedCB(_impl->getDataRef());
  310. }
  311. void CanvasRenderingContext2D::strokeText(const std::string& text, float x, float y, float maxWidth)
  312. {
  313. // SE_LOGD("CanvasRenderingContext2D::strokeText: %s, %f, %f, %f\n", text.c_str(), x, y, maxWidth);
  314. if (text.empty())
  315. return;
  316. recreateBufferIfNeeded();
  317. _impl->strokeText(text, x, y, maxWidth);
  318. if (_canvasBufferUpdatedCB != nullptr)
  319. _canvasBufferUpdatedCB(_impl->getDataRef());
  320. }
  321. cocos2d::Size CanvasRenderingContext2D::measureText(const std::string& text)
  322. {
  323. // SE_LOGD("CanvasRenderingContext2D::measureText: %s\n", text.c_str());
  324. return cocos2d::Size(_impl->measureText(text), 0);
  325. }
  326. CanvasGradient* CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1)
  327. {
  328. return nullptr;
  329. }
  330. void CanvasRenderingContext2D::save()
  331. {
  332. _impl->saveContext();
  333. }
  334. void CanvasRenderingContext2D::beginPath()
  335. {
  336. _impl->beginPath();
  337. }
  338. void CanvasRenderingContext2D::closePath()
  339. {
  340. _impl->closePath();
  341. }
  342. void CanvasRenderingContext2D::moveTo(float x, float y)
  343. {
  344. _impl->moveTo(x, y);
  345. }
  346. void CanvasRenderingContext2D::lineTo(float x, float y)
  347. {
  348. _impl->lineTo(x, y);
  349. }
  350. void CanvasRenderingContext2D::stroke()
  351. {
  352. _impl->stroke();
  353. if (_canvasBufferUpdatedCB != nullptr)
  354. _canvasBufferUpdatedCB(_impl->getDataRef());
  355. }
  356. void CanvasRenderingContext2D::fill()
  357. {
  358. _impl->fill();
  359. if (_canvasBufferUpdatedCB != nullptr)
  360. _canvasBufferUpdatedCB(_impl->getDataRef());
  361. }
  362. void CanvasRenderingContext2D::restore()
  363. {
  364. _impl->restoreContext();
  365. }
  366. void CanvasRenderingContext2D::setCanvasBufferUpdatedCallback(const CanvasBufferUpdatedCallback& cb)
  367. {
  368. _canvasBufferUpdatedCB = cb;
  369. }
  370. void CanvasRenderingContext2D::setPremultiply(bool multiply)
  371. {
  372. _impl->setPremultiply(multiply);
  373. }
  374. void CanvasRenderingContext2D::set__width(float width)
  375. {
  376. // SE_LOGD("CanvasRenderingContext2D::set__width: %f\n", width);
  377. __width = width;
  378. _isBufferSizeDirty = true;
  379. recreateBufferIfNeeded();
  380. }
  381. void CanvasRenderingContext2D::set__height(float height)
  382. {
  383. // SE_LOGD("CanvasRenderingContext2D::set__height: %f\n", height);
  384. __height = height;
  385. _isBufferSizeDirty = true;
  386. recreateBufferIfNeeded();
  387. }
  388. void CanvasRenderingContext2D::set_lineWidth(float lineWidth)
  389. {
  390. _lineWidth = lineWidth;
  391. _impl->setLineWidth(lineWidth);
  392. }
  393. void CanvasRenderingContext2D::set_lineJoin(const std::string& lineJoin)
  394. {
  395. if(lineJoin.empty()) return ;
  396. _impl->setLineJoin(lineJoin);
  397. }
  398. void CanvasRenderingContext2D::set_lineCap(const std::string& lineCap)
  399. {
  400. if(lineCap.empty()) return ;
  401. _impl->setLineCap(lineCap);
  402. }
  403. /*
  404. * support format e.g.: "oblique bold small-caps 18px Arial"
  405. * "italic bold small-caps 25px Arial"
  406. * "italic 25px Arial"
  407. * */
  408. void CanvasRenderingContext2D::set_font(const std::string& font)
  409. {
  410. if (_font != font)
  411. {
  412. _font = font;
  413. std::string fontName = "sans-serif";
  414. std::string fontSizeStr = "30";
  415. std::regex re("\\s*((\\d+)([\\.]\\d+)?)px\\s+([^\\r\\n]*)");
  416. std::match_results<std::string::const_iterator> results;
  417. if (std::regex_search(_font.cbegin(), _font.cend(), results, re))
  418. {
  419. fontSizeStr = results[2].str();
  420. // support get font name from `60px American` or `60px "American abc-abc_abc"`
  421. // support get font name contain space,example `times new roman`
  422. // if regex rule that does not conform to the rules,such as Chinese,it defaults to sans-serif
  423. std::match_results<std::string::const_iterator> fontResults;
  424. std::regex fontRe("([\\w\\s-]+|\"[\\w\\s-]+\"$)");
  425. if(std::regex_match(results[4].str(), fontResults, fontRe))
  426. {
  427. fontName = results[4].str();
  428. }
  429. }
  430. float fontSize = atof(fontSizeStr.c_str());
  431. bool isBold = font.find("bold", 0) != std::string::npos;
  432. bool isItalic = font.find("italic", 0) != std::string::npos;
  433. bool isSmallCaps = font.find("small-caps", 0) != std::string::npos;
  434. bool isOblique = font.find("oblique", 0) != std::string::npos;
  435. //font-style: italic, oblique, normal
  436. //font-weight: normal, bold
  437. //font-variant: normal, small-caps
  438. _impl->updateFont(fontName, fontSize, isBold, isItalic, isOblique, isSmallCaps);
  439. }
  440. }
  441. void CanvasRenderingContext2D::set_textAlign(const std::string& textAlign)
  442. {
  443. // SE_LOGD("CanvasRenderingContext2D::set_textAlign: %s\n", textAlign.c_str());
  444. if (textAlign == "left")
  445. {
  446. _impl->setTextAlign(CanvasTextAlign::LEFT);
  447. }
  448. else if (textAlign == "center" || textAlign == "middle")
  449. {
  450. _impl->setTextAlign(CanvasTextAlign::CENTER);
  451. }
  452. else if (textAlign == "right")
  453. {
  454. _impl->setTextAlign(CanvasTextAlign::RIGHT);
  455. }
  456. else
  457. {
  458. assert(false);
  459. }
  460. }
  461. void CanvasRenderingContext2D::set_textBaseline(const std::string& textBaseline)
  462. {
  463. // SE_LOGD("CanvasRenderingContext2D::set_textBaseline: %s\n", textBaseline.c_str());
  464. if (textBaseline == "top")
  465. {
  466. _impl->setTextBaseline(CanvasTextBaseline::TOP);
  467. }
  468. else if (textBaseline == "middle")
  469. {
  470. _impl->setTextBaseline(CanvasTextBaseline::MIDDLE);
  471. }
  472. else if (textBaseline == "bottom" || textBaseline == "alphabetic") //REFINE:, how to deal with alphabetic, currently we handle it as bottom mode.
  473. {
  474. _impl->setTextBaseline(CanvasTextBaseline::BOTTOM);
  475. }
  476. else
  477. {
  478. assert(false);
  479. }
  480. }
  481. void CanvasRenderingContext2D::set_fillStyle(const std::string& fillStyle)
  482. {
  483. CSSColorParser::Color color = CSSColorParser::parse(fillStyle);
  484. _impl->setFillStyle(color.r/255.0f, color.g/255.0f, color.b/255.0f, color.a);
  485. // SE_LOGD("CanvasRenderingContext2D::set_fillStyle: %s, (%d, %d, %d, %f)\n", fillStyle.c_str(), color.r, color.g, color.b, color.a);
  486. }
  487. void CanvasRenderingContext2D::set_strokeStyle(const std::string& strokeStyle)
  488. {
  489. CSSColorParser::Color color = CSSColorParser::parse(strokeStyle);
  490. _impl->setStrokeStyle(color.r/255.0f, color.g/255.0f, color.b/255.0f, color.a);
  491. }
  492. void CanvasRenderingContext2D::set_globalCompositeOperation(const std::string& globalCompositeOperation)
  493. {
  494. // SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
  495. }
  496. void CanvasRenderingContext2D::_fillImageData(const Data& imageData, float imageWidth, float imageHeight, float offsetX, float offsetY)
  497. {
  498. _impl->_fillImageData(imageData, imageWidth, imageHeight, offsetX, offsetY);
  499. if (_canvasBufferUpdatedCB != nullptr)
  500. _canvasBufferUpdatedCB(_impl->getDataRef());
  501. }
  502. // transform
  503. //REFINE:
  504. void CanvasRenderingContext2D::translate(float x, float y)
  505. {
  506. // SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
  507. }
  508. void CanvasRenderingContext2D::scale(float x, float y)
  509. {
  510. // SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
  511. }
  512. void CanvasRenderingContext2D::rotate(float angle)
  513. {
  514. // SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
  515. }
  516. void CanvasRenderingContext2D::transform(float a, float b, float c, float d, float e, float f)
  517. {
  518. // SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
  519. }
  520. void CanvasRenderingContext2D::setTransform(float a, float b, float c, float d, float e, float f)
  521. {
  522. // SE_LOGE("%s isn't implemented!\n", __FUNCTION__);
  523. }
  524. NS_CC_END