| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 #include "core/paint/BoxBorderPainter.h" | 6 #include "core/paint/BoxBorderPainter.h" |
| 7 | 7 |
| 8 #include "core/paint/BoxPainter.h" | 8 #include "core/paint/BoxPainter.h" |
| 9 #include "core/paint/PaintInfo.h" | 9 #include "core/paint/PaintInfo.h" |
| 10 #include "core/style/BorderEdge.h" | 10 #include "core/style/BorderEdge.h" |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 if (maxRadii > newRect.width()) { | 277 if (maxRadii > newRect.width()) { |
| 278 newRect.move(newRect.width() - maxRadii, 0); | 278 newRect.move(newRect.width() - maxRadii, 0); |
| 279 newRect.setWidth(maxRadii); | 279 newRect.setWidth(maxRadii); |
| 280 } | 280 } |
| 281 break; | 281 break; |
| 282 } | 282 } |
| 283 | 283 |
| 284 return FloatRoundedRect(newRect, newRadii); | 284 return FloatRoundedRect(newRect, newRadii); |
| 285 } | 285 } |
| 286 | 286 |
| 287 struct BoxBorderInfo { | |
| 288 STACK_ALLOCATED(); | |
| 289 public: | |
| 290 BoxBorderInfo(const ComputedStyle& style, BackgroundBleedAvoidance bleedAvoi
dance, | |
| 291 bool includeLogicalLeftEdge, bool includeLogicalRightEdge) | |
| 292 : style(style) | |
| 293 , bleedAvoidance(bleedAvoidance) | |
| 294 , includeLogicalLeftEdge(includeLogicalLeftEdge) | |
| 295 , includeLogicalRightEdge(includeLogicalRightEdge) | |
| 296 , visibleEdgeCount(0) | |
| 297 , firstVisibleEdge(0) | |
| 298 , visibleEdgeSet(0) | |
| 299 , isUniformStyle(true) | |
| 300 , isUniformWidth(true) | |
| 301 , isUniformColor(true) | |
| 302 , hasAlpha(false) | |
| 303 { | |
| 304 | |
| 305 style.getBorderEdgeInfo(edges, includeLogicalLeftEdge, includeLogicalRig
htEdge); | |
| 306 | |
| 307 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(edges); ++i) { | |
| 308 const BorderEdge& edge = edges[i]; | |
| 309 | |
| 310 if (!edge.shouldRender()) { | |
| 311 if (edge.presentButInvisible()) { | |
| 312 isUniformWidth = false; | |
| 313 isUniformColor = false; | |
| 314 } | |
| 315 | |
| 316 continue; | |
| 317 } | |
| 318 | |
| 319 visibleEdgeCount++; | |
| 320 visibleEdgeSet |= edgeFlagForSide(static_cast<BoxSide>(i)); | |
| 321 | |
| 322 hasAlpha = hasAlpha || edge.color.hasAlpha(); | |
| 323 | |
| 324 if (visibleEdgeCount == 1) { | |
| 325 firstVisibleEdge = i; | |
| 326 continue; | |
| 327 } | |
| 328 | |
| 329 isUniformStyle = isUniformStyle && (edge.borderStyle() == edges[firs
tVisibleEdge].borderStyle()); | |
| 330 isUniformWidth = isUniformWidth && (edge.width == edges[firstVisible
Edge].width); | |
| 331 isUniformColor = isUniformColor && (edge.color == edges[firstVisible
Edge].color); | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 const ComputedStyle& style; | |
| 336 const BackgroundBleedAvoidance bleedAvoidance; | |
| 337 const bool includeLogicalLeftEdge; | |
| 338 const bool includeLogicalRightEdge; | |
| 339 | |
| 340 BorderEdge edges[4]; | |
| 341 | |
| 342 unsigned visibleEdgeCount; | |
| 343 unsigned firstVisibleEdge; | |
| 344 BorderEdgeFlags visibleEdgeSet; | |
| 345 | |
| 346 bool isUniformStyle; | |
| 347 bool isUniformWidth; | |
| 348 bool isUniformColor; | |
| 349 bool hasAlpha; | |
| 350 }; | |
| 351 | |
| 352 LayoutRectOutsets doubleStripeInsets(const BorderEdge edges[], BorderEdge::Doubl
eBorderStripe stripe) | 287 LayoutRectOutsets doubleStripeInsets(const BorderEdge edges[], BorderEdge::Doubl
eBorderStripe stripe) |
| 353 { | 288 { |
| 354 // Insets are representes as negative outsets. | 289 // Insets are representes as negative outsets. |
| 355 return LayoutRectOutsets( | 290 return LayoutRectOutsets( |
| 356 -edges[BSTop].getDoubleBorderStripeWidth(stripe), | 291 -edges[BSTop].getDoubleBorderStripeWidth(stripe), |
| 357 -edges[BSRight].getDoubleBorderStripeWidth(stripe), | 292 -edges[BSRight].getDoubleBorderStripeWidth(stripe), |
| 358 -edges[BSBottom].getDoubleBorderStripeWidth(stripe), | 293 -edges[BSBottom].getDoubleBorderStripeWidth(stripe), |
| 359 -edges[BSLeft].getDoubleBorderStripeWidth(stripe)); | 294 -edges[BSLeft].getDoubleBorderStripeWidth(stripe)); |
| 360 } | 295 } |
| 361 | 296 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 context->fillDRRect(adjustedOuter, inner, color); | 348 context->fillDRRect(adjustedOuter, inner, color); |
| 414 break; | 349 break; |
| 415 } | 350 } |
| 416 // fall through | 351 // fall through |
| 417 default: | 352 default: |
| 418 context->fillDRRect(outer, inner, color); | 353 context->fillDRRect(outer, inner, color); |
| 419 break; | 354 break; |
| 420 } | 355 } |
| 421 } | 356 } |
| 422 | 357 |
| 423 void drawDoubleBorder(GraphicsContext* context, const BoxBorderInfo& borderInfo,
const LayoutRect& borderRect, | 358 bool bleedAvoidanceIsClipping(BackgroundBleedAvoidance bleedAvoidance) |
| 424 const FloatRoundedRect& outerBorder, const FloatRoundedRect& innerBorder) | |
| 425 { | 359 { |
| 426 ASSERT(borderInfo.isUniformColor); | 360 return bleedAvoidance == BackgroundBleedClipOnly || bleedAvoidance == Backgr
oundBleedClipLayer; |
| 427 ASSERT(borderInfo.isUniformStyle); | 361 } |
| 428 ASSERT(borderInfo.edges[borderInfo.firstVisibleEdge].borderStyle() == DOUBLE
); | |
| 429 ASSERT(borderInfo.visibleEdgeSet == AllBorderEdges); | |
| 430 | 362 |
| 431 const Color color = borderInfo.edges[borderInfo.firstVisibleEdge].color; | 363 } // anonymous namespace |
| 364 |
| 365 void BoxBorderPainter::drawDoubleBorder(GraphicsContext* context, const LayoutRe
ct& borderRect) const |
| 366 { |
| 367 ASSERT(m_isUniformColor); |
| 368 ASSERT(m_isUniformStyle); |
| 369 ASSERT(firstEdge().borderStyle() == DOUBLE); |
| 370 ASSERT(m_visibleEdgeSet == AllBorderEdges); |
| 371 |
| 372 const Color color = firstEdge().color; |
| 432 | 373 |
| 433 // outer stripe | 374 // outer stripe |
| 434 const LayoutRectOutsets outerThirdInsets = | 375 const LayoutRectOutsets outerThirdInsets = |
| 435 doubleStripeInsets(borderInfo.edges, BorderEdge::DoubleBorderStripeOuter
); | 376 doubleStripeInsets(m_edges, BorderEdge::DoubleBorderStripeOuter); |
| 436 const FloatRoundedRect outerThirdRect = borderInfo.style.getRoundedInnerBord
erFor(borderRect, | 377 const FloatRoundedRect outerThirdRect = m_style.getRoundedInnerBorderFor(bor
derRect, |
| 437 outerThirdInsets, borderInfo.includeLogicalLeftEdge, borderInfo.includeL
ogicalRightEdge); | 378 outerThirdInsets, m_includeLogicalLeftEdge, m_includeLogicalRightEdge); |
| 438 drawBleedAdjustedDRRect(context, borderInfo.bleedAvoidance, outerBorder, out
erThirdRect, color); | 379 drawBleedAdjustedDRRect(context, m_bleedAvoidance, m_outer, outerThirdRect,
color); |
| 439 | 380 |
| 440 // inner stripe | 381 // inner stripe |
| 441 const LayoutRectOutsets innerThirdInsets = | 382 const LayoutRectOutsets innerThirdInsets = |
| 442 doubleStripeInsets(borderInfo.edges, BorderEdge::DoubleBorderStripeInner
); | 383 doubleStripeInsets(m_edges, BorderEdge::DoubleBorderStripeInner); |
| 443 const FloatRoundedRect innerThirdRect = borderInfo.style.getRoundedInnerBord
erFor(borderRect, | 384 const FloatRoundedRect innerThirdRect = m_style.getRoundedInnerBorderFor(bor
derRect, |
| 444 innerThirdInsets, borderInfo.includeLogicalLeftEdge, borderInfo.includeL
ogicalRightEdge); | 385 innerThirdInsets, m_includeLogicalLeftEdge, m_includeLogicalRightEdge); |
| 445 context->fillDRRect(innerThirdRect, innerBorder, color); | 386 context->fillDRRect(innerThirdRect, m_inner, color); |
| 446 } | 387 } |
| 447 | 388 |
| 448 bool paintBorderFastPath(GraphicsContext* context, const BoxBorderInfo& info, | 389 bool BoxBorderPainter::paintBorderFastPath(GraphicsContext* context, const Layou
tRect& borderRect) const |
| 449 const LayoutRect& borderRect, const FloatRoundedRect& outer, const FloatRoun
dedRect& inner) | |
| 450 { | 390 { |
| 451 if (!info.isUniformColor || !info.isUniformStyle || !inner.isRenderable()) | 391 if (!m_isUniformColor || !m_isUniformStyle || !m_inner.isRenderable()) |
| 452 return false; | 392 return false; |
| 453 | 393 |
| 454 const BorderEdge& firstEdge = info.edges[info.firstVisibleEdge]; | 394 if (firstEdge().borderStyle() != SOLID && firstEdge().borderStyle() != DOUBL
E) |
| 455 if (firstEdge.borderStyle() != SOLID && firstEdge.borderStyle() != DOUBLE) | |
| 456 return false; | 395 return false; |
| 457 | 396 |
| 458 if (info.visibleEdgeSet == AllBorderEdges) { | 397 if (m_visibleEdgeSet == AllBorderEdges) { |
| 459 if (firstEdge.borderStyle() == SOLID) { | 398 if (firstEdge().borderStyle() == SOLID) { |
| 460 if (info.isUniformWidth && !outer.isRounded()) { | 399 if (m_isUniformWidth && !m_outer.isRounded()) { |
| 461 // 4-side, solid, uniform-width, rectangular border => one drawR
ect() | 400 // 4-side, solid, uniform-width, rectangular border => one drawR
ect() |
| 462 drawSolidBorderRect(context, outer.rect(), firstEdge.width, firs
tEdge.color); | 401 drawSolidBorderRect(context, m_outer.rect(), firstEdge().width,
firstEdge().color); |
| 463 } else { | 402 } else { |
| 464 // 4-side, solid border => one drawDRRect() | 403 // 4-side, solid border => one drawDRRect() |
| 465 drawBleedAdjustedDRRect(context, info.bleedAvoidance, outer, inn
er, firstEdge.color); | 404 drawBleedAdjustedDRRect(context, m_bleedAvoidance, m_outer, m_in
ner, firstEdge().color); |
| 466 } | 405 } |
| 467 } else { | 406 } else { |
| 468 // 4-side, double border => 2x drawDRRect() | 407 // 4-side, double border => 2x drawDRRect() |
| 469 ASSERT(firstEdge.borderStyle() == DOUBLE); | 408 ASSERT(firstEdge().borderStyle() == DOUBLE); |
| 470 drawDoubleBorder(context, info, borderRect, outer, inner); | 409 drawDoubleBorder(context, borderRect); |
| 471 } | 410 } |
| 472 | 411 |
| 473 return true; | 412 return true; |
| 474 } | 413 } |
| 475 | 414 |
| 476 // This is faster than the normal complex border path only if it avoids crea
ting transparency | 415 // This is faster than the normal complex border path only if it avoids crea
ting transparency |
| 477 // layers (when the border is translucent). | 416 // layers (when the border is translucent). |
| 478 if (firstEdge.borderStyle() == SOLID && !outer.isRounded() && info.hasAlpha)
{ | 417 if (firstEdge().borderStyle() == SOLID && !m_outer.isRounded() && m_hasAlpha
) { |
| 479 ASSERT(info.visibleEdgeSet != AllBorderEdges); | 418 ASSERT(m_visibleEdgeSet != AllBorderEdges); |
| 480 // solid, rectangular border => one drawPath() | 419 // solid, rectangular border => one drawPath() |
| 481 Path path; | 420 Path path; |
| 482 | 421 |
| 483 for (int i = BSTop; i <= BSLeft; ++i) { | 422 for (int i = BSTop; i <= BSLeft; ++i) { |
| 484 const BorderEdge& currEdge = info.edges[i]; | 423 const BorderEdge& currEdge = m_edges[i]; |
| 485 if (currEdge.shouldRender()) | 424 if (currEdge.shouldRender()) |
| 486 path.addRect(calculateSideRect(outer, currEdge, i)); | 425 path.addRect(calculateSideRect(m_outer, currEdge, i)); |
| 487 } | 426 } |
| 488 | 427 |
| 489 context->setFillRule(RULE_NONZERO); | 428 context->setFillRule(RULE_NONZERO); |
| 490 context->setFillColor(firstEdge.color); | 429 context->setFillColor(firstEdge().color); |
| 491 context->fillPath(path); | 430 context->fillPath(path); |
| 492 | 431 |
| 493 return true; | 432 return true; |
| 494 } | 433 } |
| 495 | 434 |
| 496 return false; | 435 return false; |
| 497 } | 436 } |
| 498 | 437 |
| 499 bool bleedAvoidanceIsClipping(BackgroundBleedAvoidance bleedAvoidance) | 438 BoxBorderPainter::BoxBorderPainter(const LayoutRect& borderRect, const ComputedS
tyle& style, |
| 439 const IntRect& clipRect, BackgroundBleedAvoidance bleedAvoidance, |
| 440 bool includeLogicalLeftEdge, bool includeLogicalRightEdge) |
| 441 : m_style(style) |
| 442 , m_bleedAvoidance(bleedAvoidance) |
| 443 , m_includeLogicalLeftEdge(includeLogicalLeftEdge) |
| 444 , m_includeLogicalRightEdge(includeLogicalRightEdge) |
| 445 , m_visibleEdgeCount(0) |
| 446 , m_firstVisibleEdge(0) |
| 447 , m_visibleEdgeSet(0) |
| 448 , m_isUniformStyle(true) |
| 449 , m_isUniformWidth(true) |
| 450 , m_isUniformColor(true) |
| 451 , m_hasAlpha(false) |
| 500 { | 452 { |
| 501 return bleedAvoidance == BackgroundBleedClipOnly || bleedAvoidance == Backgr
oundBleedClipLayer; | 453 style.getBorderEdgeInfo(m_edges, includeLogicalLeftEdge, includeLogicalRight
Edge); |
| 454 |
| 455 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_edges); ++i) { |
| 456 const BorderEdge& edge = m_edges[i]; |
| 457 |
| 458 if (!edge.shouldRender()) { |
| 459 if (edge.presentButInvisible()) { |
| 460 m_isUniformWidth = false; |
| 461 m_isUniformColor = false; |
| 462 } |
| 463 |
| 464 continue; |
| 465 } |
| 466 |
| 467 m_visibleEdgeCount++; |
| 468 m_visibleEdgeSet |= edgeFlagForSide(static_cast<BoxSide>(i)); |
| 469 |
| 470 m_hasAlpha |= edge.color.hasAlpha(); |
| 471 |
| 472 if (m_visibleEdgeCount == 1) { |
| 473 m_firstVisibleEdge = i; |
| 474 continue; |
| 475 } |
| 476 |
| 477 m_isUniformStyle &= edge.borderStyle() == m_edges[m_firstVisibleEdge].bo
rderStyle(); |
| 478 m_isUniformWidth &= edge.width == m_edges[m_firstVisibleEdge].width; |
| 479 m_isUniformColor &= edge.color == m_edges[m_firstVisibleEdge].color; |
| 480 } |
| 481 |
| 482 // No need to compute the rrects if we don't have any borders to draw. |
| 483 if (!m_visibleEdgeSet) |
| 484 return; |
| 485 |
| 486 m_outer = style.getRoundedBorderFor(borderRect, includeLogicalLeftEdge, incl
udeLogicalRightEdge); |
| 487 m_inner = style.getRoundedInnerBorderFor(borderRect, includeLogicalLeftEdge,
includeLogicalRightEdge); |
| 488 |
| 489 // If no corner intersects the clip region, we can pretend the outer border
is |
| 490 // rectangular to improve performance. |
| 491 // FIXME: why is this predicated on uniform style & solid edges? |
| 492 if (m_isUniformStyle |
| 493 && firstEdge().borderStyle() == SOLID |
| 494 && m_outer.isRounded() |
| 495 && BoxPainter::allCornersClippedOut(m_outer, clipRect)) |
| 496 m_outer.setRadii(FloatRoundedRect::Radii()); |
| 502 } | 497 } |
| 503 | 498 |
| 504 } // anonymous namespace | 499 void BoxBorderPainter::paintBorder(const PaintInfo& info, const LayoutRect& rect
) const |
| 505 | |
| 506 void BoxBorderPainter::paintBorder(LayoutBoxModelObject& obj, const PaintInfo& i
nfo, | |
| 507 const LayoutRect& rect, const ComputedStyle& style, BackgroundBleedAvoidance
bleedAvoidance, | |
| 508 bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const | |
| 509 { | 500 { |
| 510 GraphicsContext* graphicsContext = info.context; | 501 if (!m_visibleEdgeCount || m_outer.rect().isEmpty()) |
| 511 // border-image is not affected by border-radius. | |
| 512 if (BoxPainter::paintNinePieceImage(obj, graphicsContext, rect, style, style
.borderImage())) | |
| 513 return; | 502 return; |
| 514 | 503 |
| 515 const BoxBorderInfo borderInfo(style, bleedAvoidance, includeLogicalLeftEdge
, includeLogicalRightEdge); | 504 GraphicsContext* graphicsContext = info.context; |
| 516 FloatRoundedRect outerBorder = style.getRoundedBorderFor(rect, includeLogica
lLeftEdge, includeLogicalRightEdge); | |
| 517 FloatRoundedRect innerBorder = style.getRoundedInnerBorderFor(rect, includeL
ogicalLeftEdge, includeLogicalRightEdge); | |
| 518 | 505 |
| 519 if (outerBorder.rect().isEmpty() || !borderInfo.visibleEdgeCount) | 506 if (paintBorderFastPath(graphicsContext, rect)) |
| 520 return; | 507 return; |
| 521 | 508 |
| 522 const BorderEdge& firstEdge = borderInfo.edges[borderInfo.firstVisibleEdge]; | 509 bool clipToOuterBorder = m_outer.isRounded(); |
| 523 bool haveAllSolidEdges = borderInfo.isUniformStyle && firstEdge.borderStyle(
) == SOLID; | |
| 524 | |
| 525 // If no corner intersects the clip region, we can pretend outerBorder is | |
| 526 // rectangular to improve performance. | |
| 527 if (haveAllSolidEdges && outerBorder.isRounded() && BoxPainter::allCornersCl
ippedOut(outerBorder, info.rect)) | |
| 528 outerBorder.setRadii(FloatRoundedRect::Radii()); | |
| 529 | |
| 530 if (paintBorderFastPath(graphicsContext, borderInfo, rect, outerBorder, inne
rBorder)) | |
| 531 return; | |
| 532 | |
| 533 bool clipToOuterBorder = outerBorder.isRounded(); | |
| 534 GraphicsContextStateSaver stateSaver(*graphicsContext, clipToOuterBorder); | 510 GraphicsContextStateSaver stateSaver(*graphicsContext, clipToOuterBorder); |
| 535 if (clipToOuterBorder) { | 511 if (clipToOuterBorder) { |
| 536 // For BackgroundBleedClip{Only,Layer}, the outer rrect clip is already
applied. | 512 // For BackgroundBleedClip{Only,Layer}, the outer rrect clip is already
applied. |
| 537 if (!bleedAvoidanceIsClipping(bleedAvoidance)) | 513 if (!bleedAvoidanceIsClipping(m_bleedAvoidance)) |
| 538 graphicsContext->clipRoundedRect(outerBorder); | 514 graphicsContext->clipRoundedRect(m_outer); |
| 539 | 515 |
| 540 // For BackgroundBleedBackgroundOverBorder, we're going to draw an opaqu
e background over | 516 // For BackgroundBleedBackgroundOverBorder, we're going to draw an opaqu
e background over |
| 541 // the inner rrect - so clipping is not needed (nor desirable due to bac
kdrop bleeding). | 517 // the inner rrect - so clipping is not needed (nor desirable due to bac
kdrop bleeding). |
| 542 if (bleedAvoidance != BackgroundBleedBackgroundOverBorder && innerBorder
.isRenderable() && !innerBorder.isEmpty()) | 518 if (m_bleedAvoidance != BackgroundBleedBackgroundOverBorder && m_inner.i
sRenderable() && !m_inner.isEmpty()) |
| 543 graphicsContext->clipOutRoundedRect(innerBorder); | 519 graphicsContext->clipOutRoundedRect(m_inner); |
| 544 } | 520 } |
| 545 | 521 |
| 546 // If only one edge visible antialiasing doesn't create seams | 522 // If only one edge visible antialiasing doesn't create seams |
| 547 bool antialias = BoxPainter::shouldAntialiasLines(graphicsContext) || border
Info.visibleEdgeCount == 1; | 523 bool antialias = BoxPainter::shouldAntialiasLines(graphicsContext) || m_visi
bleEdgeCount == 1; |
| 548 if (borderInfo.hasAlpha) { | 524 if (m_hasAlpha) { |
| 549 paintTranslucentBorderSides(graphicsContext, style, outerBorder, innerBo
rder, borderInfo.edges, | 525 paintTranslucentBorderSides(graphicsContext, antialias); |
| 550 borderInfo.visibleEdgeSet, bleedAvoidance, includeLogicalLeftEdge, inclu
deLogicalRightEdge, antialias); | |
| 551 } else { | 526 } else { |
| 552 paintBorderSides(graphicsContext, style, outerBorder, innerBorder, borde
rInfo.edges, | 527 paintBorderSides(graphicsContext, m_visibleEdgeSet, antialias); |
| 553 borderInfo.visibleEdgeSet, bleedAvoidance, includeLogicalLeftEdge, inclu
deLogicalRightEdge, antialias); | |
| 554 } | 528 } |
| 555 } | 529 } |
| 556 | 530 |
| 557 void BoxBorderPainter::paintTranslucentBorderSides(GraphicsContext* graphicsCont
ext, | 531 void BoxBorderPainter::paintTranslucentBorderSides(GraphicsContext* graphicsCont
ext, |
| 558 const ComputedStyle& style, const FloatRoundedRect& outerBorder, const Float
RoundedRect& innerBorder, | 532 bool antialias) const |
| 559 const BorderEdge edges[], BorderEdgeFlags edgesToDraw, BackgroundBleedAvoida
nce bleedAvoidance, | |
| 560 bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias) | |
| 561 { | 533 { |
| 562 // willBeOverdrawn assumes that we draw in order: top, bottom, left, right. | 534 // willBeOverdrawn assumes that we draw in order: top, bottom, left, right. |
| 563 // This is different from BoxSide enum order. | 535 // This is different from BoxSide enum order. |
| 564 static const BoxSide paintOrder[] = { BSTop, BSBottom, BSLeft, BSRight }; | 536 static const BoxSide paintOrder[] = { BSTop, BSBottom, BSLeft, BSRight }; |
| 565 | 537 |
| 538 BorderEdgeFlags edgesToDraw = m_visibleEdgeSet; |
| 566 while (edgesToDraw) { | 539 while (edgesToDraw) { |
| 567 // Find undrawn edges sharing a color. | 540 // Find undrawn edges sharing a color. |
| 568 Color commonColor; | 541 Color commonColor; |
| 569 | 542 |
| 570 BorderEdgeFlags commonColorEdgeSet = 0; | 543 BorderEdgeFlags commonColorEdgeSet = 0; |
| 571 for (size_t i = 0; i < sizeof(paintOrder) / sizeof(paintOrder[0]); ++i)
{ | 544 for (size_t i = 0; i < sizeof(paintOrder) / sizeof(paintOrder[0]); ++i)
{ |
| 572 BoxSide currSide = paintOrder[i]; | 545 BoxSide currSide = paintOrder[i]; |
| 573 if (!includesEdge(edgesToDraw, currSide)) | 546 if (!includesEdge(edgesToDraw, currSide)) |
| 574 continue; | 547 continue; |
| 575 | 548 |
| 576 bool includeEdge; | 549 bool includeEdge; |
| 577 if (!commonColorEdgeSet) { | 550 if (!commonColorEdgeSet) { |
| 578 commonColor = edges[currSide].color; | 551 commonColor = m_edges[currSide].color; |
| 579 includeEdge = true; | 552 includeEdge = true; |
| 580 } else { | 553 } else { |
| 581 includeEdge = edges[currSide].color == commonColor; | 554 includeEdge = m_edges[currSide].color == commonColor; |
| 582 } | 555 } |
| 583 | 556 |
| 584 if (includeEdge) | 557 if (includeEdge) |
| 585 commonColorEdgeSet |= edgeFlagForSide(currSide); | 558 commonColorEdgeSet |= edgeFlagForSide(currSide); |
| 586 } | 559 } |
| 587 | 560 |
| 588 bool useTransparencyLayer = includesAdjacentEdges(commonColorEdgeSet) &&
commonColor.hasAlpha(); | 561 bool useTransparencyLayer = includesAdjacentEdges(commonColorEdgeSet) &&
commonColor.hasAlpha(); |
| 589 if (useTransparencyLayer) { | 562 if (useTransparencyLayer) { |
| 590 graphicsContext->beginLayer(static_cast<float>(commonColor.alpha())
/ 255); | 563 graphicsContext->beginLayer(static_cast<float>(commonColor.alpha())
/ 255); |
| 591 commonColor = Color(commonColor.red(), commonColor.green(), commonCo
lor.blue()); | 564 commonColor = Color(commonColor.red(), commonColor.green(), commonCo
lor.blue()); |
| 592 } | 565 } |
| 593 | 566 |
| 594 paintBorderSides(graphicsContext, style, outerBorder, innerBorder, edges
, commonColorEdgeSet, | 567 paintBorderSides(graphicsContext, commonColorEdgeSet, antialias, &common
Color); |
| 595 bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, ant
ialias, &commonColor); | |
| 596 | 568 |
| 597 if (useTransparencyLayer) | 569 if (useTransparencyLayer) |
| 598 graphicsContext->endLayer(); | 570 graphicsContext->endLayer(); |
| 599 | 571 |
| 600 edgesToDraw &= ~commonColorEdgeSet; | 572 edgesToDraw &= ~commonColorEdgeSet; |
| 601 } | 573 } |
| 602 } | 574 } |
| 603 | 575 |
| 604 void BoxBorderPainter::paintOneBorderSide(GraphicsContext* graphicsContext, cons
t ComputedStyle& style, | 576 void BoxBorderPainter::paintOneBorderSide(GraphicsContext* graphicsContext, |
| 605 const FloatRoundedRect& outerBorder, const FloatRoundedRect& innerBorder, co
nst FloatRect& sideRect, | 577 const FloatRect& sideRect, BoxSide side, BoxSide adjacentSide1, BoxSide adja
centSide2, |
| 606 BoxSide side, BoxSide adjacentSide1, BoxSide adjacentSide2, const BorderEdge
edges[], const Path* path, | 578 const Path* path, bool antialias, const Color* overrideColor) const |
| 607 BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool i
ncludeLogicalRightEdge, | |
| 608 bool antialias, const Color* overrideColor) | |
| 609 { | 579 { |
| 610 const BorderEdge& edgeToRender = edges[side]; | 580 const BorderEdge& edgeToRender = m_edges[side]; |
| 611 ASSERT(edgeToRender.width); | 581 ASSERT(edgeToRender.width); |
| 612 const BorderEdge& adjacentEdge1 = edges[adjacentSide1]; | 582 const BorderEdge& adjacentEdge1 = m_edges[adjacentSide1]; |
| 613 const BorderEdge& adjacentEdge2 = edges[adjacentSide2]; | 583 const BorderEdge& adjacentEdge2 = m_edges[adjacentSide2]; |
| 614 | |
| 615 bool mitreAdjacentSide1 = joinRequiresMitre(side, adjacentSide1, edges, !ant
ialias); | |
| 616 bool mitreAdjacentSide2 = joinRequiresMitre(side, adjacentSide2, edges, !ant
ialias); | |
| 617 | |
| 618 bool adjacentSide1StylesMatch = colorsMatchAtCorner(side, adjacentSide1, edg
es); | |
| 619 bool adjacentSide2StylesMatch = colorsMatchAtCorner(side, adjacentSide2, edg
es); | |
| 620 | 584 |
| 621 const Color& colorToPaint = overrideColor ? *overrideColor : edgeToRender.co
lor; | 585 const Color& colorToPaint = overrideColor ? *overrideColor : edgeToRender.co
lor; |
| 622 | 586 |
| 623 if (path) { | 587 if (path) { |
| 588 bool adjacentSide1StylesMatch = colorsMatchAtCorner(side, adjacentSide1,
m_edges); |
| 589 bool adjacentSide2StylesMatch = colorsMatchAtCorner(side, adjacentSide2,
m_edges); |
| 590 |
| 624 GraphicsContextStateSaver stateSaver(*graphicsContext); | 591 GraphicsContextStateSaver stateSaver(*graphicsContext); |
| 625 if (innerBorder.isRenderable()) | 592 if (m_inner.isRenderable()) |
| 626 clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, sid
e, adjacentSide1StylesMatch, adjacentSide2StylesMatch); | 593 clipBorderSidePolygon(graphicsContext, side, adjacentSide1StylesMatc
h, adjacentSide2StylesMatch); |
| 627 else | 594 else |
| 628 clipBorderSideForComplexInnerPath(graphicsContext, outerBorder, inne
rBorder, side, edges); | 595 clipBorderSideForComplexInnerPath(graphicsContext, side); |
| 629 float thickness = std::max(std::max(edgeToRender.width, adjacentEdge1.wi
dth), adjacentEdge2.width); | 596 float thickness = std::max(std::max(edgeToRender.width, adjacentEdge1.wi
dth), adjacentEdge2.width); |
| 630 drawBoxSideFromPath(graphicsContext, LayoutRect(outerBorder.rect()), *pa
th, edges, edgeToRender.width, thickness, side, style, | 597 drawBoxSideFromPath(graphicsContext, LayoutRect(m_outer.rect()), *path,
edgeToRender.width, |
| 631 colorToPaint, edgeToRender.borderStyle(), bleedAvoidance, includeLog
icalLeftEdge, includeLogicalRightEdge); | 598 thickness, side, colorToPaint, edgeToRender.borderStyle()); |
| 632 } else { | 599 } else { |
| 633 bool clipForStyle = styleRequiresClipPolygon(edgeToRender.borderStyle())
&& (mitreAdjacentSide1 || mitreAdjacentSide2); | 600 bool mitreAdjacentSide1 = joinRequiresMitre(side, adjacentSide1, m_edges
, !antialias); |
| 634 bool clipAdjacentSide1 = colorNeedsAntiAliasAtCorner(side, adjacentSide1
, edges) && mitreAdjacentSide1; | 601 bool mitreAdjacentSide2 = joinRequiresMitre(side, adjacentSide2, m_edges
, !antialias); |
| 635 bool clipAdjacentSide2 = colorNeedsAntiAliasAtCorner(side, adjacentSide2
, edges) && mitreAdjacentSide2; | 602 |
| 603 bool clipForStyle = styleRequiresClipPolygon(edgeToRender.borderStyle()) |
| 604 && (mitreAdjacentSide1 || mitreAdjacentSide2); |
| 605 bool clipAdjacentSide1 = colorNeedsAntiAliasAtCorner(side, adjacentSide1
, m_edges) && mitreAdjacentSide1; |
| 606 bool clipAdjacentSide2 = colorNeedsAntiAliasAtCorner(side, adjacentSide2
, m_edges) && mitreAdjacentSide2; |
| 636 bool shouldClip = clipForStyle || clipAdjacentSide1 || clipAdjacentSide2
; | 607 bool shouldClip = clipForStyle || clipAdjacentSide1 || clipAdjacentSide2
; |
| 637 | 608 |
| 638 GraphicsContextStateSaver clipStateSaver(*graphicsContext, shouldClip); | 609 GraphicsContextStateSaver clipStateSaver(*graphicsContext, shouldClip); |
| 639 if (shouldClip) { | 610 if (shouldClip) { |
| 640 bool aliasAdjacentSide1 = clipAdjacentSide1 || (clipForStyle && mitr
eAdjacentSide1); | 611 bool aliasAdjacentSide1 = clipAdjacentSide1 || (clipForStyle && mitr
eAdjacentSide1); |
| 641 bool aliasAdjacentSide2 = clipAdjacentSide2 || (clipForStyle && mitr
eAdjacentSide2); | 612 bool aliasAdjacentSide2 = clipAdjacentSide2 || (clipForStyle && mitr
eAdjacentSide2); |
| 642 clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, sid
e, !aliasAdjacentSide1, !aliasAdjacentSide2); | 613 clipBorderSidePolygon(graphicsContext, side, !aliasAdjacentSide1, !a
liasAdjacentSide2); |
| 643 // Since we clipped, no need to draw with a mitre. | 614 // Since we clipped, no need to draw with a mitre. |
| 644 mitreAdjacentSide1 = false; | 615 mitreAdjacentSide1 = false; |
| 645 mitreAdjacentSide2 = false; | 616 mitreAdjacentSide2 = false; |
| 646 } | 617 } |
| 647 | 618 |
| 648 ObjectPainter::drawLineForBoxSide(graphicsContext, sideRect.x(), sideRec
t.y(), sideRect.maxX(), sideRect.maxY(), side, colorToPaint, edgeToRender.border
Style(), | 619 ObjectPainter::drawLineForBoxSide(graphicsContext, sideRect.x(), sideRec
t.y(), |
| 620 sideRect.maxX(), sideRect.maxY(), side, colorToPaint, edgeToRender.b
orderStyle(), |
| 649 mitreAdjacentSide1 ? adjacentEdge1.width : 0, mitreAdjacentSide2 ? a
djacentEdge2.width : 0, antialias); | 621 mitreAdjacentSide1 ? adjacentEdge1.width : 0, mitreAdjacentSide2 ? a
djacentEdge2.width : 0, antialias); |
| 650 } | 622 } |
| 651 } | 623 } |
| 652 | 624 |
| 653 void BoxBorderPainter::paintBorderSides(GraphicsContext* graphicsContext, const
ComputedStyle& style, | 625 void BoxBorderPainter::paintBorderSides(GraphicsContext* graphicsContext, Border
EdgeFlags edgeSet, |
| 654 const FloatRoundedRect& outerBorder, const FloatRoundedRect& innerBorder, co
nst BorderEdge edges[], | 626 bool antialias, const Color* overrideColor) const |
| 655 BorderEdgeFlags edgeSet, BackgroundBleedAvoidance bleedAvoidance, bool inclu
deLogicalLeftEdge, | |
| 656 bool includeLogicalRightEdge, bool antialias, const Color* overrideColor) | |
| 657 { | 627 { |
| 658 bool renderRadii = outerBorder.isRounded(); | 628 bool renderRadii = m_outer.isRounded(); |
| 659 | 629 |
| 660 Path roundedPath; | 630 Path roundedPath; |
| 661 if (renderRadii) | 631 if (renderRadii) |
| 662 roundedPath.addRoundedRect(outerBorder); | 632 roundedPath.addRoundedRect(m_outer); |
| 663 | 633 |
| 664 // The inner border adjustment for bleed avoidance mode BackgroundBleedBackg
roundOverBorder | 634 // The inner border adjustment for bleed avoidance mode BackgroundBleedBackg
roundOverBorder |
| 665 // is only applied to sideRect, which is okay since BackgroundBleedBackgroun
dOverBorder | 635 // is only applied to sideRect, which is okay since BackgroundBleedBackgroun
dOverBorder |
| 666 // is only to be used for solid borders and the shape of the border painted
by drawBoxSideFromPath | 636 // is only to be used for solid borders and the shape of the border painted
by drawBoxSideFromPath |
| 667 // only depends on sideRect when painting solid borders. | 637 // only depends on sideRect when painting solid borders. |
| 668 | 638 |
| 669 if (edges[BSTop].shouldRender() && includesEdge(edgeSet, BSTop)) { | 639 if (includesEdge(edgeSet, BSTop)) { |
| 670 FloatRect sideRect = outerBorder.rect(); | 640 const BorderEdge& edge = m_edges[BSTop]; |
| 671 sideRect.setHeight(edges[BSTop].width); | 641 ASSERT(edge.shouldRender()); |
| 672 | 642 |
| 673 bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSTop].bo
rderStyle()) || borderWillArcInnerEdge(innerBorder.radii().topLeft(), innerBorde
r.radii().topRight())); | 643 FloatRect sideRect = m_outer.rect(); |
| 674 paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sid
eRect, BSTop, BSLeft, BSRight, edges, usePath ? &roundedPath : 0, bleedAvoidance
, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor); | 644 sideRect.setHeight(edge.width); |
| 645 |
| 646 bool usePath = renderRadii && (borderStyleHasInnerDetail(edge.borderStyl
e()) |
| 647 || borderWillArcInnerEdge(m_inner.radii().topLeft(), m_inner.radii()
.topRight())); |
| 648 paintOneBorderSide(graphicsContext, sideRect, BSTop, BSLeft, BSRight, |
| 649 usePath ? &roundedPath : 0, antialias, overrideColor); |
| 675 } | 650 } |
| 676 | 651 |
| 677 if (edges[BSBottom].shouldRender() && includesEdge(edgeSet, BSBottom)) { | 652 if (includesEdge(edgeSet, BSBottom)) { |
| 678 FloatRect sideRect = outerBorder.rect(); | 653 const BorderEdge& edge = m_edges[BSBottom]; |
| 679 sideRect.shiftYEdgeTo(sideRect.maxY() - edges[BSBottom].width); | 654 ASSERT(edge.shouldRender()); |
| 680 | 655 |
| 681 bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSBottom]
.borderStyle()) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), inne
rBorder.radii().bottomRight())); | 656 FloatRect sideRect = m_outer.rect(); |
| 682 paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sid
eRect, BSBottom, BSLeft, BSRight, edges, usePath ? &roundedPath : 0, bleedAvoida
nce, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor); | 657 sideRect.shiftYEdgeTo(sideRect.maxY() - edge.width); |
| 658 |
| 659 bool usePath = renderRadii && (borderStyleHasInnerDetail(edge.borderStyl
e()) |
| 660 || borderWillArcInnerEdge(m_inner.radii().bottomLeft(), m_inner.radi
i().bottomRight())); |
| 661 paintOneBorderSide(graphicsContext, sideRect, BSBottom, BSLeft, BSRight, |
| 662 usePath ? &roundedPath : 0, antialias, overrideColor); |
| 683 } | 663 } |
| 684 | 664 |
| 685 if (edges[BSLeft].shouldRender() && includesEdge(edgeSet, BSLeft)) { | 665 if (includesEdge(edgeSet, BSLeft)) { |
| 686 FloatRect sideRect = outerBorder.rect(); | 666 const BorderEdge& edge = m_edges[BSLeft]; |
| 687 sideRect.setWidth(edges[BSLeft].width); | 667 ASSERT(edge.shouldRender()); |
| 688 | 668 |
| 689 bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSLeft].b
orderStyle()) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), innerB
order.radii().topLeft())); | 669 FloatRect sideRect = m_outer.rect(); |
| 690 paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sid
eRect, BSLeft, BSTop, BSBottom, edges, usePath ? &roundedPath : 0, bleedAvoidanc
e, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor); | 670 sideRect.setWidth(edge.width); |
| 671 |
| 672 bool usePath = renderRadii && (borderStyleHasInnerDetail(edge.borderStyl
e()) |
| 673 || borderWillArcInnerEdge(m_inner.radii().bottomLeft(), m_inner.radi
i().topLeft())); |
| 674 paintOneBorderSide(graphicsContext, sideRect, BSLeft, BSTop, BSBottom, |
| 675 usePath ? &roundedPath : 0, antialias, overrideColor); |
| 691 } | 676 } |
| 692 | 677 |
| 693 if (edges[BSRight].shouldRender() && includesEdge(edgeSet, BSRight)) { | 678 if (includesEdge(edgeSet, BSRight)) { |
| 694 FloatRect sideRect = outerBorder.rect(); | 679 const BorderEdge& edge = m_edges[BSRight]; |
| 695 sideRect.shiftXEdgeTo(sideRect.maxX() - edges[BSRight].width); | 680 ASSERT(edge.shouldRender()); |
| 696 | 681 |
| 697 bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSRight].
borderStyle()) || borderWillArcInnerEdge(innerBorder.radii().bottomRight(), inne
rBorder.radii().topRight())); | 682 FloatRect sideRect = m_outer.rect(); |
| 698 paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sid
eRect, BSRight, BSTop, BSBottom, edges, usePath ? &roundedPath : 0, bleedAvoidan
ce, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor); | 683 sideRect.shiftXEdgeTo(sideRect.maxX() - edge.width); |
| 684 |
| 685 bool usePath = renderRadii && (borderStyleHasInnerDetail(edge.borderStyl
e()) |
| 686 || borderWillArcInnerEdge(m_inner.radii().bottomRight(), m_inner.rad
ii().topRight())); |
| 687 paintOneBorderSide(graphicsContext, sideRect, BSRight, BSTop, BSBottom, |
| 688 usePath ? &roundedPath : 0, antialias, overrideColor); |
| 699 } | 689 } |
| 700 } | 690 } |
| 701 | 691 |
| 702 void BoxBorderPainter::drawBoxSideFromPath(GraphicsContext* graphicsContext, | 692 void BoxBorderPainter::drawBoxSideFromPath(GraphicsContext* graphicsContext, |
| 703 const LayoutRect& borderRect, const Path& borderPath, const BorderEdge edges
[], float thickness, | 693 const LayoutRect& borderRect, const Path& borderPath, float thickness, float
drawThickness, |
| 704 float drawThickness, BoxSide side, const ComputedStyle& style, Color color,
EBorderStyle borderStyle, | 694 BoxSide side, Color color, EBorderStyle borderStyle) const |
| 705 BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool i
ncludeLogicalRightEdge) | |
| 706 { | 695 { |
| 707 if (thickness <= 0) | 696 if (thickness <= 0) |
| 708 return; | 697 return; |
| 709 | 698 |
| 710 if (borderStyle == DOUBLE && thickness < 3) | 699 if (borderStyle == DOUBLE && thickness < 3) |
| 711 borderStyle = SOLID; | 700 borderStyle = SOLID; |
| 712 | 701 |
| 713 switch (borderStyle) { | 702 switch (borderStyle) { |
| 714 case BNONE: | 703 case BNONE: |
| 715 case BHIDDEN: | 704 case BHIDDEN: |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 752 // FIXME: stroking the border path causes issues with tight corners: | 741 // FIXME: stroking the border path causes issues with tight corners: |
| 753 // https://bugs.webkit.org/show_bug.cgi?id=58711 | 742 // https://bugs.webkit.org/show_bug.cgi?id=58711 |
| 754 // Also, to get the best appearance we should stroke a path between the
two borders. | 743 // Also, to get the best appearance we should stroke a path between the
two borders. |
| 755 graphicsContext->strokePath(borderPath); | 744 graphicsContext->strokePath(borderPath); |
| 756 return; | 745 return; |
| 757 } | 746 } |
| 758 case DOUBLE: { | 747 case DOUBLE: { |
| 759 // Draw inner border line | 748 // Draw inner border line |
| 760 { | 749 { |
| 761 GraphicsContextStateSaver stateSaver(*graphicsContext); | 750 GraphicsContextStateSaver stateSaver(*graphicsContext); |
| 762 const LayoutRectOutsets innerInsets = doubleStripeInsets(edges, Bord
erEdge::DoubleBorderStripeInner); | 751 const LayoutRectOutsets innerInsets = doubleStripeInsets(m_edges, Bo
rderEdge::DoubleBorderStripeInner); |
| 763 FloatRoundedRect innerClip = style.getRoundedInnerBorderFor(borderRe
ct, | 752 FloatRoundedRect innerClip = m_style.getRoundedInnerBorderFor(border
Rect, innerInsets, |
| 764 innerInsets, includeLogicalLeftEdge, includeLogicalRightEdge); | 753 m_includeLogicalLeftEdge, m_includeLogicalRightEdge); |
| 765 | 754 |
| 766 graphicsContext->clipRoundedRect(innerClip); | 755 graphicsContext->clipRoundedRect(innerClip); |
| 767 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges,
thickness, drawThickness, side, style, color, SOLID, bleedAvoidance, includeLogi
calLeftEdge, includeLogicalRightEdge); | 756 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickne
ss, drawThickness, |
| 757 side, color, SOLID); |
| 768 } | 758 } |
| 769 | 759 |
| 770 // Draw outer border line | 760 // Draw outer border line |
| 771 { | 761 { |
| 772 GraphicsContextStateSaver stateSaver(*graphicsContext); | 762 GraphicsContextStateSaver stateSaver(*graphicsContext); |
| 773 LayoutRect outerRect = borderRect; | 763 LayoutRect outerRect = borderRect; |
| 774 LayoutRectOutsets outerInsets = doubleStripeInsets(edges, BorderEdge
::DoubleBorderStripeOuter); | 764 LayoutRectOutsets outerInsets = doubleStripeInsets(m_edges, BorderEd
ge::DoubleBorderStripeOuter); |
| 775 | 765 |
| 776 if (bleedAvoidanceIsClipping(bleedAvoidance)) { | 766 if (bleedAvoidanceIsClipping(m_bleedAvoidance)) { |
| 777 outerRect.inflate(1); | 767 outerRect.inflate(1); |
| 778 outerInsets.setTop(outerInsets.top() - 1); | 768 outerInsets.setTop(outerInsets.top() - 1); |
| 779 outerInsets.setRight(outerInsets.right() - 1); | 769 outerInsets.setRight(outerInsets.right() - 1); |
| 780 outerInsets.setBottom(outerInsets.bottom() - 1); | 770 outerInsets.setBottom(outerInsets.bottom() - 1); |
| 781 outerInsets.setLeft(outerInsets.left() - 1); | 771 outerInsets.setLeft(outerInsets.left() - 1); |
| 782 } | 772 } |
| 783 | 773 |
| 784 FloatRoundedRect outerClip = style.getRoundedInnerBorderFor(outerRec
t, outerInsets, | 774 FloatRoundedRect outerClip = m_style.getRoundedInnerBorderFor(outerR
ect, outerInsets, |
| 785 includeLogicalLeftEdge, includeLogicalRightEdge); | 775 m_includeLogicalLeftEdge, m_includeLogicalRightEdge); |
| 786 graphicsContext->clipOutRoundedRect(outerClip); | 776 graphicsContext->clipOutRoundedRect(outerClip); |
| 787 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges,
thickness, drawThickness, side, style, color, SOLID, bleedAvoidance, includeLogi
calLeftEdge, includeLogicalRightEdge); | 777 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickne
ss, drawThickness, |
| 778 side, color, SOLID); |
| 788 } | 779 } |
| 789 return; | 780 return; |
| 790 } | 781 } |
| 791 case RIDGE: | 782 case RIDGE: |
| 792 case GROOVE: | 783 case GROOVE: |
| 793 { | 784 { |
| 794 EBorderStyle s1; | 785 EBorderStyle s1; |
| 795 EBorderStyle s2; | 786 EBorderStyle s2; |
| 796 if (borderStyle == GROOVE) { | 787 if (borderStyle == GROOVE) { |
| 797 s1 = INSET; | 788 s1 = INSET; |
| 798 s2 = OUTSET; | 789 s2 = OUTSET; |
| 799 } else { | 790 } else { |
| 800 s1 = OUTSET; | 791 s1 = OUTSET; |
| 801 s2 = INSET; | 792 s2 = INSET; |
| 802 } | 793 } |
| 803 | 794 |
| 804 // Paint full border | 795 // Paint full border |
| 805 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thic
kness, drawThickness, side, style, color, s1, bleedAvoidance, includeLogicalLeft
Edge, includeLogicalRightEdge); | 796 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickness,
drawThickness, |
| 797 side, color, s1); |
| 806 | 798 |
| 807 // Paint inner only | 799 // Paint inner only |
| 808 GraphicsContextStateSaver stateSaver(*graphicsContext); | 800 GraphicsContextStateSaver stateSaver(*graphicsContext); |
| 809 LayoutUnit topWidth = edges[BSTop].usedWidth() / 2; | 801 LayoutUnit topWidth = m_edges[BSTop].usedWidth() / 2; |
| 810 LayoutUnit bottomWidth = edges[BSBottom].usedWidth() / 2; | 802 LayoutUnit bottomWidth = m_edges[BSBottom].usedWidth() / 2; |
| 811 LayoutUnit leftWidth = edges[BSLeft].usedWidth() / 2; | 803 LayoutUnit leftWidth = m_edges[BSLeft].usedWidth() / 2; |
| 812 LayoutUnit rightWidth = edges[BSRight].usedWidth() / 2; | 804 LayoutUnit rightWidth = m_edges[BSRight].usedWidth() / 2; |
| 813 | 805 |
| 814 FloatRoundedRect clipRect = style.getRoundedInnerBorderFor(borderRect, | 806 FloatRoundedRect clipRect = m_style.getRoundedInnerBorderFor(borderRect, |
| 815 LayoutRectOutsets(-topWidth, -rightWidth, -bottomWidth, -leftWidth), | 807 LayoutRectOutsets(-topWidth, -rightWidth, -bottomWidth, -leftWidth), |
| 816 includeLogicalLeftEdge, includeLogicalRightEdge); | 808 m_includeLogicalLeftEdge, m_includeLogicalRightEdge); |
| 817 | 809 |
| 818 graphicsContext->clipRoundedRect(clipRect); | 810 graphicsContext->clipRoundedRect(clipRect); |
| 819 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thic
kness, drawThickness, side, style, color, s2, bleedAvoidance, includeLogicalLeft
Edge, includeLogicalRightEdge); | 811 drawBoxSideFromPath(graphicsContext, borderRect, borderPath, thickness,
drawThickness, |
| 812 side, color, s2); |
| 820 return; | 813 return; |
| 821 } | 814 } |
| 822 case INSET: | 815 case INSET: |
| 823 if (side == BSTop || side == BSLeft) | 816 if (side == BSTop || side == BSLeft) |
| 824 color = color.dark(); | 817 color = color.dark(); |
| 825 break; | 818 break; |
| 826 case OUTSET: | 819 case OUTSET: |
| 827 if (side == BSBottom || side == BSRight) | 820 if (side == BSBottom || side == BSRight) |
| 828 color = color.dark(); | 821 color = color.dark(); |
| 829 break; | 822 break; |
| 830 default: | 823 default: |
| 831 break; | 824 break; |
| 832 } | 825 } |
| 833 | 826 |
| 834 graphicsContext->setStrokeStyle(NoStroke); | 827 graphicsContext->setStrokeStyle(NoStroke); |
| 835 graphicsContext->setFillColor(color); | 828 graphicsContext->setFillColor(color); |
| 836 graphicsContext->drawRect(pixelSnappedIntRect(borderRect)); | 829 graphicsContext->drawRect(pixelSnappedIntRect(borderRect)); |
| 837 } | 830 } |
| 838 | 831 |
| 839 void BoxBorderPainter::clipBorderSideForComplexInnerPath(GraphicsContext* graphi
csContext, | 832 void BoxBorderPainter::clipBorderSideForComplexInnerPath(GraphicsContext* graphi
csContext, |
| 840 const FloatRoundedRect& outerBorder, const FloatRoundedRect& innerBorder, | 833 BoxSide side) const |
| 841 BoxSide side, const BorderEdge edges[]) | |
| 842 { | 834 { |
| 843 graphicsContext->clip(calculateSideRectIncludingInner(outerBorder, edges, si
de)); | 835 graphicsContext->clip(calculateSideRectIncludingInner(m_outer, m_edges, side
)); |
| 844 FloatRoundedRect adjustedInnerRect = calculateAdjustedInnerBorder(innerBorde
r, side); | 836 FloatRoundedRect adjustedInnerRect = calculateAdjustedInnerBorder(m_inner, s
ide); |
| 845 if (!adjustedInnerRect.isEmpty()) | 837 if (!adjustedInnerRect.isEmpty()) |
| 846 graphicsContext->clipOutRoundedRect(adjustedInnerRect); | 838 graphicsContext->clipOutRoundedRect(adjustedInnerRect); |
| 847 } | 839 } |
| 848 | 840 |
| 849 void BoxBorderPainter::clipBorderSidePolygon(GraphicsContext* graphicsContext, | 841 void BoxBorderPainter::clipBorderSidePolygon(GraphicsContext* graphicsContext, B
oxSide side, |
| 850 const FloatRoundedRect& outerBorder, const FloatRoundedRect& innerBorder, Bo
xSide side, | 842 bool firstEdgeMatches, bool secondEdgeMatches) const |
| 851 bool firstEdgeMatches, bool secondEdgeMatches) | |
| 852 { | 843 { |
| 853 FloatPoint quad[4]; | 844 FloatPoint quad[4]; |
| 854 | 845 |
| 855 const LayoutRect outerRect(outerBorder.rect()); | 846 const LayoutRect outerRect(m_outer.rect()); |
| 856 const LayoutRect innerRect(innerBorder.rect()); | 847 const LayoutRect innerRect(m_inner.rect()); |
| 857 | |
| 858 FloatPoint centerPoint(innerRect.location().x().toFloat() + innerRect.width(
).toFloat() / 2, innerRect.location().y().toFloat() + innerRect.height().toFloat
() / 2); | |
| 859 | 848 |
| 860 // For each side, create a quad that encompasses all parts of that side that
may draw, | 849 // For each side, create a quad that encompasses all parts of that side that
may draw, |
| 861 // including areas inside the innerBorder. | 850 // including areas inside the innerBorder. |
| 862 // | 851 // |
| 863 // 0----------------3 | 852 // 0----------------3 |
| 864 // 0 \ / 0 | 853 // 0 \ / 0 |
| 865 // |\ 1----------- 2 /| | 854 // |\ 1----------- 2 /| |
| 866 // | 1 1 | | 855 // | 1 1 | |
| 867 // | | | | | 856 // | | | | |
| 868 // | | | | | 857 // | | | | |
| 869 // | 2 2 | | 858 // | 2 2 | |
| 870 // |/ 1------------2 \| | 859 // |/ 1------------2 \| |
| 871 // 3 / \ 3 | 860 // 3 / \ 3 |
| 872 // 0----------------3 | 861 // 0----------------3 |
| 873 // | 862 // |
| 874 switch (side) { | 863 switch (side) { |
| 875 case BSTop: | 864 case BSTop: |
| 876 quad[0] = FloatPoint(outerRect.minXMinYCorner()); | 865 quad[0] = FloatPoint(outerRect.minXMinYCorner()); |
| 877 quad[1] = FloatPoint(innerRect.minXMinYCorner()); | 866 quad[1] = FloatPoint(innerRect.minXMinYCorner()); |
| 878 quad[2] = FloatPoint(innerRect.maxXMinYCorner()); | 867 quad[2] = FloatPoint(innerRect.maxXMinYCorner()); |
| 879 quad[3] = FloatPoint(outerRect.maxXMinYCorner()); | 868 quad[3] = FloatPoint(outerRect.maxXMinYCorner()); |
| 880 | 869 |
| 881 if (!innerBorder.radii().topLeft().isZero()) { | 870 if (!m_inner.radii().topLeft().isZero()) { |
| 882 findIntersection(quad[0], quad[1], | 871 findIntersection(quad[0], quad[1], |
| 883 FloatPoint( | 872 FloatPoint( |
| 884 quad[1].x() + innerBorder.radii().topLeft().width(), | 873 quad[1].x() + m_inner.radii().topLeft().width(), |
| 885 quad[1].y()), | 874 quad[1].y()), |
| 886 FloatPoint( | 875 FloatPoint( |
| 887 quad[1].x(), | 876 quad[1].x(), |
| 888 quad[1].y() + innerBorder.radii().topLeft().height()), | 877 quad[1].y() + m_inner.radii().topLeft().height()), |
| 889 quad[1]); | 878 quad[1]); |
| 890 } | 879 } |
| 891 | 880 |
| 892 if (!innerBorder.radii().topRight().isZero()) { | 881 if (!m_inner.radii().topRight().isZero()) { |
| 893 findIntersection(quad[3], quad[2], | 882 findIntersection(quad[3], quad[2], |
| 894 FloatPoint( | 883 FloatPoint( |
| 895 quad[2].x() - innerBorder.radii().topRight().width(), | 884 quad[2].x() - m_inner.radii().topRight().width(), |
| 896 quad[2].y()), | 885 quad[2].y()), |
| 897 FloatPoint( | 886 FloatPoint( |
| 898 quad[2].x(), | 887 quad[2].x(), |
| 899 quad[2].y() + innerBorder.radii().topRight().height()), | 888 quad[2].y() + m_inner.radii().topRight().height()), |
| 900 quad[2]); | 889 quad[2]); |
| 901 } | 890 } |
| 902 break; | 891 break; |
| 903 | 892 |
| 904 case BSLeft: | 893 case BSLeft: |
| 905 quad[0] = FloatPoint(outerRect.minXMinYCorner()); | 894 quad[0] = FloatPoint(outerRect.minXMinYCorner()); |
| 906 quad[1] = FloatPoint(innerRect.minXMinYCorner()); | 895 quad[1] = FloatPoint(innerRect.minXMinYCorner()); |
| 907 quad[2] = FloatPoint(innerRect.minXMaxYCorner()); | 896 quad[2] = FloatPoint(innerRect.minXMaxYCorner()); |
| 908 quad[3] = FloatPoint(outerRect.minXMaxYCorner()); | 897 quad[3] = FloatPoint(outerRect.minXMaxYCorner()); |
| 909 | 898 |
| 910 if (!innerBorder.radii().topLeft().isZero()) { | 899 if (!m_inner.radii().topLeft().isZero()) { |
| 911 findIntersection(quad[0], quad[1], | 900 findIntersection(quad[0], quad[1], |
| 912 FloatPoint( | 901 FloatPoint( |
| 913 quad[1].x() + innerBorder.radii().topLeft().width(), | 902 quad[1].x() + m_inner.radii().topLeft().width(), |
| 914 quad[1].y()), | 903 quad[1].y()), |
| 915 FloatPoint( | 904 FloatPoint( |
| 916 quad[1].x(), | 905 quad[1].x(), |
| 917 quad[1].y() + innerBorder.radii().topLeft().height()), | 906 quad[1].y() + m_inner.radii().topLeft().height()), |
| 918 quad[1]); | 907 quad[1]); |
| 919 } | 908 } |
| 920 | 909 |
| 921 if (!innerBorder.radii().bottomLeft().isZero()) { | 910 if (!m_inner.radii().bottomLeft().isZero()) { |
| 922 findIntersection(quad[3], quad[2], | 911 findIntersection(quad[3], quad[2], |
| 923 FloatPoint( | 912 FloatPoint( |
| 924 quad[2].x() + innerBorder.radii().bottomLeft().width(), | 913 quad[2].x() + m_inner.radii().bottomLeft().width(), |
| 925 quad[2].y()), | 914 quad[2].y()), |
| 926 FloatPoint( | 915 FloatPoint( |
| 927 quad[2].x(), | 916 quad[2].x(), |
| 928 quad[2].y() - innerBorder.radii().bottomLeft().height()), | 917 quad[2].y() - m_inner.radii().bottomLeft().height()), |
| 929 quad[2]); | 918 quad[2]); |
| 930 } | 919 } |
| 931 break; | 920 break; |
| 932 | 921 |
| 933 case BSBottom: | 922 case BSBottom: |
| 934 quad[0] = FloatPoint(outerRect.minXMaxYCorner()); | 923 quad[0] = FloatPoint(outerRect.minXMaxYCorner()); |
| 935 quad[1] = FloatPoint(innerRect.minXMaxYCorner()); | 924 quad[1] = FloatPoint(innerRect.minXMaxYCorner()); |
| 936 quad[2] = FloatPoint(innerRect.maxXMaxYCorner()); | 925 quad[2] = FloatPoint(innerRect.maxXMaxYCorner()); |
| 937 quad[3] = FloatPoint(outerRect.maxXMaxYCorner()); | 926 quad[3] = FloatPoint(outerRect.maxXMaxYCorner()); |
| 938 | 927 |
| 939 if (!innerBorder.radii().bottomLeft().isZero()) { | 928 if (!m_inner.radii().bottomLeft().isZero()) { |
| 940 findIntersection(quad[0], quad[1], | 929 findIntersection(quad[0], quad[1], |
| 941 FloatPoint( | 930 FloatPoint( |
| 942 quad[1].x() + innerBorder.radii().bottomLeft().width(), | 931 quad[1].x() + m_inner.radii().bottomLeft().width(), |
| 943 quad[1].y()), | 932 quad[1].y()), |
| 944 FloatPoint( | 933 FloatPoint( |
| 945 quad[1].x(), | 934 quad[1].x(), |
| 946 quad[1].y() - innerBorder.radii().bottomLeft().height()), | 935 quad[1].y() - m_inner.radii().bottomLeft().height()), |
| 947 quad[1]); | 936 quad[1]); |
| 948 } | 937 } |
| 949 | 938 |
| 950 if (!innerBorder.radii().bottomRight().isZero()) { | 939 if (!m_inner.radii().bottomRight().isZero()) { |
| 951 findIntersection(quad[3], quad[2], | 940 findIntersection(quad[3], quad[2], |
| 952 FloatPoint( | 941 FloatPoint( |
| 953 quad[2].x() - innerBorder.radii().bottomRight().width(), | 942 quad[2].x() - m_inner.radii().bottomRight().width(), |
| 954 quad[2].y()), | 943 quad[2].y()), |
| 955 FloatPoint( | 944 FloatPoint( |
| 956 quad[2].x(), | 945 quad[2].x(), |
| 957 quad[2].y() - innerBorder.radii().bottomRight().height()), | 946 quad[2].y() - m_inner.radii().bottomRight().height()), |
| 958 quad[2]); | 947 quad[2]); |
| 959 } | 948 } |
| 960 break; | 949 break; |
| 961 | 950 |
| 962 case BSRight: | 951 case BSRight: |
| 963 quad[0] = FloatPoint(outerRect.maxXMinYCorner()); | 952 quad[0] = FloatPoint(outerRect.maxXMinYCorner()); |
| 964 quad[1] = FloatPoint(innerRect.maxXMinYCorner()); | 953 quad[1] = FloatPoint(innerRect.maxXMinYCorner()); |
| 965 quad[2] = FloatPoint(innerRect.maxXMaxYCorner()); | 954 quad[2] = FloatPoint(innerRect.maxXMaxYCorner()); |
| 966 quad[3] = FloatPoint(outerRect.maxXMaxYCorner()); | 955 quad[3] = FloatPoint(outerRect.maxXMaxYCorner()); |
| 967 | 956 |
| 968 if (!innerBorder.radii().topRight().isZero()) { | 957 if (!m_inner.radii().topRight().isZero()) { |
| 969 findIntersection(quad[0], quad[1], | 958 findIntersection(quad[0], quad[1], |
| 970 FloatPoint( | 959 FloatPoint( |
| 971 quad[1].x() - innerBorder.radii().topRight().width(), | 960 quad[1].x() - m_inner.radii().topRight().width(), |
| 972 quad[1].y()), | 961 quad[1].y()), |
| 973 FloatPoint( | 962 FloatPoint( |
| 974 quad[1].x(), | 963 quad[1].x(), |
| 975 quad[1].y() + innerBorder.radii().topRight().height()), | 964 quad[1].y() + m_inner.radii().topRight().height()), |
| 976 quad[1]); | 965 quad[1]); |
| 977 } | 966 } |
| 978 | 967 |
| 979 if (!innerBorder.radii().bottomRight().isZero()) { | 968 if (!m_inner.radii().bottomRight().isZero()) { |
| 980 findIntersection(quad[3], quad[2], | 969 findIntersection(quad[3], quad[2], |
| 981 FloatPoint( | 970 FloatPoint( |
| 982 quad[2].x() - innerBorder.radii().bottomRight().width(), | 971 quad[2].x() - m_inner.radii().bottomRight().width(), |
| 983 quad[2].y()), | 972 quad[2].y()), |
| 984 FloatPoint( | 973 FloatPoint( |
| 985 quad[2].x(), | 974 quad[2].x(), |
| 986 quad[2].y() - innerBorder.radii().bottomRight().height()), | 975 quad[2].y() - m_inner.radii().bottomRight().height()), |
| 987 quad[2]); | 976 quad[2]); |
| 988 } | 977 } |
| 989 break; | 978 break; |
| 990 } | 979 } |
| 991 | 980 |
| 992 // If the border matches both of its adjacent sides, don't anti-alias the cl
ip, and | 981 // If the border matches both of its adjacent sides, don't anti-alias the cl
ip, and |
| 993 // if neither side matches, anti-alias the clip. | 982 // if neither side matches, anti-alias the clip. |
| 994 if (firstEdgeMatches == secondEdgeMatches) { | 983 if (firstEdgeMatches == secondEdgeMatches) { |
| 995 graphicsContext->clipPolygon(4, quad, !firstEdgeMatches); | 984 graphicsContext->clipPolygon(4, quad, !firstEdgeMatches); |
| 996 return; | 985 return; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1028 | 1017 |
| 1029 FloatPoint secondQuad[4]; | 1018 FloatPoint secondQuad[4]; |
| 1030 secondQuad[0] = quad[0]; | 1019 secondQuad[0] = quad[0]; |
| 1031 secondQuad[1] = FloatPoint(quad[0].x() - r1 * cx, quad[0].y() - r1 * cy); | 1020 secondQuad[1] = FloatPoint(quad[0].x() - r1 * cx, quad[0].y() - r1 * cy); |
| 1032 secondQuad[2] = quad[2]; | 1021 secondQuad[2] = quad[2]; |
| 1033 secondQuad[3] = quad[3]; | 1022 secondQuad[3] = quad[3]; |
| 1034 graphicsContext->clipPolygon(4, secondQuad, !secondEdgeMatches); | 1023 graphicsContext->clipPolygon(4, secondQuad, !secondEdgeMatches); |
| 1035 } | 1024 } |
| 1036 | 1025 |
| 1037 } // namespace blink | 1026 } // namespace blink |
| OLD | NEW |