1 /* 2 * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "config.h" 27 28 #include "Path.h" 29 #include "FloatRect.h" 30 #include "StrokeStyleApplier.h" 31 #include <wtf/java/JavaEnv.h> 32 #include "NotImplemented.h" 33 #include "GraphicsContextJava.h" 34 #include "RQRef.h" 35 #include "GraphicsContext.h" 36 #include "ImageBuffer.h" 37 38 #include <wtf/text/WTFString.h> 39 40 #include "com_sun_webkit_graphics_WCPathIterator.h" 41 42 43 namespace WebCore { 44 45 static GraphicsContext& scratchContext() 46 { 47 static std::unique_ptr<ImageBuffer> img = ImageBuffer::create(FloatSize(1.f, 1.f), Unaccelerated); 48 static GraphicsContext &context = img->context(); 49 return context; 50 } 51 52 RefPtr<RQRef> createEmptyPath() 53 { 54 JNIEnv* env = WebCore_GetJavaEnv(); 55 static jmethodID mid = env->GetMethodID(PG_GetGraphicsManagerClass(env), 56 "createWCPath", "()Lcom/sun/webkit/graphics/WCPath;"); 57 ASSERT(mid); 58 59 JLObject ref(env->CallObjectMethod(PL_GetGraphicsManager(env), mid)); 60 ASSERT(ref); 61 CheckAndClearException(env); 62 return RQRef::create(ref); 63 } 64 65 RefPtr<RQRef> copyPath(RefPtr<RQRef> p) 66 { 67 if (!p) { 68 return createEmptyPath(); 69 } 70 JNIEnv* env = WebCore_GetJavaEnv(); 71 72 static jmethodID mid = env->GetMethodID(PG_GetGraphicsManagerClass(env), 73 "createWCPath", 74 "(Lcom/sun/webkit/graphics/WCPath;)Lcom/sun/webkit/graphics/WCPath;"); 75 ASSERT(mid); 76 77 JLObject ref(env->CallObjectMethod(PL_GetGraphicsManager(env), mid, (jobject)*p)); 78 ASSERT(ref); 79 CheckAndClearException(env); 80 81 return RQRef::create(ref); 82 } 83 84 85 86 Path::Path() 87 : m_path(createEmptyPath()) 88 {} 89 90 Path::Path(const Path& p) 91 : m_path(copyPath(p.platformPath())) 92 {} 93 94 Path::~Path() 95 {} 96 97 Path::Path(Path&& other) 98 { 99 m_path = other.m_path; 100 other.m_path = nullptr; 101 } 102 103 Path& Path::operator=(const Path &p) 104 { 105 if (this != &p) { 106 m_path = copyPath(p.platformPath()); 107 } 108 return *this; 109 } 110 111 Path& Path::operator=(Path&& other) 112 { 113 if (this == &other) 114 return *this; 115 116 m_path = other.m_path; 117 other.m_path = nullptr; 118 return *this; 119 } 120 121 bool Path::contains(const FloatPoint& p, WindRule rule) const 122 { 123 ASSERT(m_path); 124 125 JNIEnv* env = WebCore_GetJavaEnv(); 126 127 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), "contains", 128 "(IDD)Z"); 129 ASSERT(mid); 130 131 jboolean res = env->CallBooleanMethod(*m_path, mid, (jint)rule, 132 (jdouble)p.x(), (jdouble)p.y()); 133 CheckAndClearException(env); 134 135 return jbool_to_bool(res); 136 } 137 138 FloatRect Path::boundingRect() const 139 { 140 return strokeBoundingRect(0); 141 } 142 143 FloatRect Path::strokeBoundingRect(StrokeStyleApplier *applier) const 144 { 145 ASSERT(m_path); 146 147 JNIEnv* env = WebCore_GetJavaEnv(); 148 149 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), "getBounds", 150 "()Lcom/sun/webkit/graphics/WCRectangle;"); 151 ASSERT(mid); 152 153 JLObject rect(env->CallObjectMethod(*m_path, mid)); 154 CheckAndClearException(env); 155 if (rect) { 156 static jfieldID rectxFID = env->GetFieldID(PG_GetRectangleClass(env), "x", "F"); 157 ASSERT(rectxFID); 158 static jfieldID rectyFID = env->GetFieldID(PG_GetRectangleClass(env), "y", "F"); 159 ASSERT(rectyFID); 160 static jfieldID rectwFID = env->GetFieldID(PG_GetRectangleClass(env), "w", "F"); 161 ASSERT(rectwFID); 162 static jfieldID recthFID = env->GetFieldID(PG_GetRectangleClass(env), "h", "F"); 163 ASSERT(recthFID); 164 165 FloatRect bounds( 166 float(env->GetFloatField(rect, rectxFID)), 167 float(env->GetFloatField(rect, rectyFID)), 168 float(env->GetFloatField(rect, rectwFID)), 169 float(env->GetFloatField(rect, recthFID))); 170 CheckAndClearException(env); 171 172 float thickness; 173 if (applier) { 174 GraphicsContext& gc = scratchContext(); 175 gc.save(); 176 applier->strokeStyle(&gc); 177 thickness = gc.strokeThickness(); 178 gc.restore(); 179 bounds.inflate(thickness / 2); 180 } 181 return bounds; 182 } else { 183 return FloatRect(); 184 } 185 } 186 187 void Path::clear() 188 { 189 ASSERT(m_path); 190 191 JNIEnv* env = WebCore_GetJavaEnv(); 192 193 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), 194 "clear", "()V"); 195 ASSERT(mid); 196 197 env->CallVoidMethod(*m_path, mid); 198 CheckAndClearException(env); 199 } 200 201 bool Path::isEmpty() const 202 { 203 ASSERT(m_path); 204 205 JNIEnv* env = WebCore_GetJavaEnv(); 206 207 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), 208 "isEmpty", "()Z"); 209 ASSERT(mid); 210 211 jboolean res = env->CallBooleanMethod(*m_path, mid); 212 CheckAndClearException(env); 213 214 return jbool_to_bool(res); 215 } 216 217 bool Path::hasCurrentPoint() const 218 { 219 ASSERT(m_path); 220 221 JNIEnv* env = WebCore_GetJavaEnv(); 222 223 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), 224 "hasCurrentPoint", "()Z"); 225 ASSERT(mid); 226 227 jboolean res = env->CallBooleanMethod(*m_path, mid); 228 CheckAndClearException(env); 229 230 return jbool_to_bool(res); 231 } 232 233 FloatPoint Path::currentPoint() const 234 { 235 //utatodo: return current point of subpath. 236 float quietNaN = std::numeric_limits<float>::quiet_NaN(); 237 return FloatPoint(quietNaN, quietNaN); 238 } 239 240 void Path::moveTo(const FloatPoint &p) 241 { 242 ASSERT(m_path); 243 244 JNIEnv* env = WebCore_GetJavaEnv(); 245 246 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), "moveTo", 247 "(DD)V"); 248 ASSERT(mid); 249 250 env->CallVoidMethod(*m_path, mid, (jdouble)p.x(), (jdouble)p.y()); 251 CheckAndClearException(env); 252 } 253 254 void Path::addLineTo(const FloatPoint &p) 255 { 256 ASSERT(m_path); 257 258 JNIEnv* env = WebCore_GetJavaEnv(); 259 260 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), "addLineTo", 261 "(DD)V"); 262 ASSERT(mid); 263 264 env->CallVoidMethod(*m_path, mid, (jdouble)p.x(), (jdouble)p.y()); 265 CheckAndClearException(env); 266 } 267 268 void Path::addQuadCurveTo(const FloatPoint &cp, const FloatPoint &p) 269 { 270 ASSERT(m_path); 271 272 JNIEnv* env = WebCore_GetJavaEnv(); 273 274 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), "addQuadCurveTo", 275 "(DDDD)V"); 276 ASSERT(mid); 277 278 env->CallVoidMethod(*m_path, mid, (jdouble)cp.x(), (jdouble)cp.y(), (jdouble)p.x(), (jdouble)p.y()); 279 CheckAndClearException(env); 280 } 281 282 void Path::addBezierCurveTo(const FloatPoint & controlPoint1, 283 const FloatPoint & controlPoint2, 284 const FloatPoint & controlPoint3) 285 { 286 ASSERT(m_path); 287 288 JNIEnv* env = WebCore_GetJavaEnv(); 289 290 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), 291 "addBezierCurveTo", "(DDDDDD)V"); 292 ASSERT(mid); 293 294 env->CallVoidMethod(*m_path, mid, 295 (jdouble)controlPoint1.x(), (jdouble)controlPoint1.y(), 296 (jdouble)controlPoint2.x(), (jdouble)controlPoint2.y(), 297 (jdouble)controlPoint3.x(), (jdouble)controlPoint3.y()); 298 CheckAndClearException(env); 299 } 300 301 void Path::addArcTo(const FloatPoint & p1, const FloatPoint & p2, float radius) 302 { 303 ASSERT(m_path); 304 305 JNIEnv* env = WebCore_GetJavaEnv(); 306 307 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), "addArcTo", 308 "(DDDDD)V"); 309 ASSERT(mid); 310 311 env->CallVoidMethod(*m_path, mid, 312 (jdouble)p1.x(), (jdouble)p1.y(), 313 (jdouble)p2.x(), (jdouble)p2.y(), (jdouble)radius); 314 CheckAndClearException(env); 315 } 316 317 void Path::closeSubpath() 318 { 319 ASSERT(m_path); 320 321 JNIEnv* env = WebCore_GetJavaEnv(); 322 323 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), 324 "closeSubpath", "()V"); 325 ASSERT(mid); 326 327 env->CallVoidMethod(*m_path, mid); 328 CheckAndClearException(env); 329 } 330 331 void Path::addArc(const FloatPoint & p, float radius, float startAngle, 332 float endAngle, bool clockwise) 333 { 334 ASSERT(m_path); 335 336 JNIEnv* env = WebCore_GetJavaEnv(); 337 338 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), "addArc", 339 "(DDDDDZ)V"); 340 ASSERT(mid); 341 342 env->CallVoidMethod(*m_path, mid, (jdouble)p.x(), (jdouble)p.y(), 343 (jdouble)radius, (jdouble)startAngle, (jdouble)endAngle, 344 bool_to_jbool(clockwise)); 345 CheckAndClearException(env); 346 } 347 348 void Path::addRect(const FloatRect& r) 349 { 350 ASSERT(m_path); 351 352 JNIEnv* env = WebCore_GetJavaEnv(); 353 354 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), "addRect", 355 "(DDDD)V"); 356 ASSERT(mid); 357 358 env->CallVoidMethod(*m_path, mid, (jdouble)r.x(), (jdouble)r.y(), 359 (jdouble)r.width(), (jdouble)r.height()); 360 CheckAndClearException(env); 361 } 362 363 void Path::addEllipse(FloatPoint, float, float, float, float, float, bool) 364 { 365 notImplemented(); 366 } 367 368 void Path::addPath(const Path&, const AffineTransform&) 369 { 370 notImplemented(); 371 } 372 373 void Path::addEllipse(const FloatRect& r) 374 { 375 ASSERT(m_path); 376 377 JNIEnv* env = WebCore_GetJavaEnv(); 378 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), "addEllipse", 379 "(DDDD)V"); 380 ASSERT(mid); 381 382 env->CallVoidMethod(*m_path, mid, 383 (jdouble)r.x(), (jdouble)r.y(), 384 (jdouble)r.width(), (jdouble)r.height()); 385 CheckAndClearException(env); 386 } 387 388 void Path::translate(const FloatSize &sz) 389 { 390 ASSERT(m_path); 391 392 JNIEnv* env = WebCore_GetJavaEnv(); 393 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), "translate", 394 "(DD)V"); 395 ASSERT(mid); 396 397 env->CallVoidMethod(*m_path, mid, 398 (jdouble)sz.width(), (jdouble)sz.height()); 399 CheckAndClearException(env); 400 } 401 402 void Path::transform(const AffineTransform &at) 403 { 404 ASSERT(m_path); 405 406 JNIEnv* env = WebCore_GetJavaEnv(); 407 408 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), 409 "transform", "(DDDDDD)V"); 410 ASSERT(mid); 411 412 env->CallVoidMethod(*m_path, mid, 413 (jdouble)at.a(), (jdouble)at.b(), 414 (jdouble)at.c(), (jdouble)at.d(), 415 (jdouble)at.e(), (jdouble)at.f()); 416 CheckAndClearException(env); 417 } 418 419 void Path::apply(const PathApplierFunction& function) const 420 { 421 ASSERT(m_path); 422 423 JNIEnv* env = WebCore_GetJavaEnv(); 424 425 static jmethodID mid = env->GetMethodID(PG_GetPathClass(env), 426 "getPathIterator", "()Lcom/sun/webkit/graphics/WCPathIterator;"); 427 ASSERT(mid); 428 429 JLObject iter(env->CallObjectMethod(*m_path, mid)); 430 CheckAndClearException(env); 431 432 if (iter) { 433 static jmethodID midIsDone = env->GetMethodID(PG_GetPathIteratorClass(env), 434 "isDone", "()Z"); 435 ASSERT(midIsDone); 436 437 static jmethodID midNext = env->GetMethodID(PG_GetPathIteratorClass(env), 438 "next", "()V"); 439 ASSERT(midNext); 440 441 static jmethodID midCurrentSegment = env->GetMethodID(PG_GetPathIteratorClass(env), 442 "currentSegment", "([D)I"); 443 ASSERT(midCurrentSegment); 444 445 PathElement pelement; 446 FloatPoint points[3]; 447 pelement.points = points; 448 449 JLocalRef<jdoubleArray> coords(env->NewDoubleArray(6)); 450 while(JNI_FALSE == env->CallBooleanMethod(iter, midIsDone)) { 451 jint type = env->CallBooleanMethod( 452 iter, 453 midCurrentSegment, 454 (jdoubleArray)coords); 455 jboolean isCopy = JNI_FALSE; 456 jdouble *data = env->GetDoubleArrayElements(coords, &isCopy); 457 switch (type) { 458 case com_sun_webkit_graphics_WCPathIterator_SEG_MOVETO: 459 pelement.type = PathElementMoveToPoint; 460 pelement.points[0] = FloatPoint(data[0],data[1]); 461 function(pelement); 462 break; 463 case com_sun_webkit_graphics_WCPathIterator_SEG_LINETO: 464 pelement.type = PathElementAddLineToPoint; 465 pelement.points[0] = FloatPoint(data[0],data[1]); 466 function(pelement); 467 break; 468 case com_sun_webkit_graphics_WCPathIterator_SEG_QUADTO: 469 pelement.type = PathElementAddQuadCurveToPoint; 470 pelement.points[0] = FloatPoint(data[0],data[1]); 471 pelement.points[1] = FloatPoint(data[2],data[3]); 472 function(pelement); 473 break; 474 case com_sun_webkit_graphics_WCPathIterator_SEG_CUBICTO: 475 pelement.type = PathElementAddCurveToPoint; 476 pelement.points[0] = FloatPoint(data[0],data[1]); 477 pelement.points[1] = FloatPoint(data[2],data[3]); 478 pelement.points[2] = FloatPoint(data[4],data[5]); 479 function(pelement); 480 break; 481 case com_sun_webkit_graphics_WCPathIterator_SEG_CLOSE: 482 pelement.type = PathElementCloseSubpath; 483 function(pelement); 484 break; 485 } 486 env->ReleaseDoubleArrayElements(coords, data, JNI_ABORT); 487 env->CallVoidMethod(iter, midNext); 488 } 489 CheckAndClearException(env); 490 } 491 } 492 493 }