bool SVGInlineTextBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit, LayoutUnit) { // FIXME: integrate with InlineTextBox::nodeAtPoint better. ASSERT(!isLineBreak()); PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, result.hitTestRequest(), lineLayoutItem().style()->pointerEvents()); bool isVisible = lineLayoutItem().style()->visibility() == VISIBLE; if (isVisible || !hitRules.requireVisible) { if (hitRules.canHitBoundingBox || (hitRules.canHitStroke && (lineLayoutItem().style()->svgStyle().hasStroke() || !hitRules.requireStroke)) || (hitRules.canHitFill && (lineLayoutItem().style()->svgStyle().hasFill() || !hitRules.requireFill))) { LayoutPoint boxOrigin(x(), y()); boxOrigin.moveBy(accumulatedOffset); LayoutRect rect(boxOrigin, size()); if (locationInContainer.intersects(rect)) { LineLayoutSVGInlineText lineLayoutItem = LineLayoutSVGInlineText(this->lineLayoutItem()); ASSERT(lineLayoutItem.scalingFactor()); float baseline = lineLayoutItem.scaledFont().fontMetrics().floatAscent() / lineLayoutItem.scalingFactor(); FloatPoint floatLocation = FloatPoint(locationInContainer.point()); for (const SVGTextFragment& fragment : m_textFragments) { FloatQuad fragmentQuad = fragment.boundingQuad(baseline); if (fragmentQuad.containsPoint(floatLocation)) { lineLayoutItem.updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); if (!result.addNodeToListBasedTestResult(lineLayoutItem.node(), locationInContainer, rect)) return true; } } } } } return false; }
bool SVGInlineTextBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit, LayoutUnit) { // FIXME: integrate with InlineTextBox::nodeAtPoint better. ASSERT(!isLineBreak()); PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, result.hitTestRequest(), layoutObject().style()->pointerEvents()); bool isVisible = layoutObject().style()->visibility() == VISIBLE; if (isVisible || !hitRules.requireVisible) { if (hitRules.canHitBoundingBox || (hitRules.canHitStroke && (layoutObject().style()->svgStyle().hasStroke() || !hitRules.requireStroke)) || (hitRules.canHitFill && (layoutObject().style()->svgStyle().hasFill() || !hitRules.requireFill))) { FloatPointWillBeLayoutPoint boxOrigin(x(), y()); boxOrigin.moveBy(accumulatedOffset); FloatRectWillBeLayoutRect rect(boxOrigin, size()); // FIXME: both calls to rawValue() below is temporary and should be removed once the transition // to LayoutUnit-based types is complete (crbug.com/321237) if (locationInContainer.intersects(rect.rawValue())) { layoutObject().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); if (!result.addNodeToListBasedTestResult(layoutObject().node(), locationInContainer, rect.rawValue())) return true; } } } return false; }
void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { GraphicsContext* context = paintInfo.context; RenderStyle* style = m_renderer->style(isFirstLineStyle()); Color styleTextColor = style->visitedDependentColor(CSSPropertyWebkitTextFillColor); if (styleTextColor != context->fillColor()) context->setFillColor(styleTextColor, style->colorSpace()); Color textColor = styleTextColor; const Font& font = style->font(); if (selectionState() != RenderObject::SelectionNone) { paintSelection(context, paintOffset, style, font); // Select the correct color for painting the text. Color foreground = paintInfo.forceBlackText() ? Color::black : renderer()->selectionForegroundColor(); if (foreground.isValid() && foreground != styleTextColor) context->setFillColor(foreground, style->colorSpace()); } const ShadowData* shadow = style->textShadow(); bool hasShadow = shadow; if (hasShadow) { // FIXME: it would be better if we could get the shadows top-to-bottom from the style. Vector<const ShadowData*, 4> shadows; do { shadows.append(shadow); } while ((shadow = shadow->next())); DrawLooper drawLooper; drawLooper.addUnmodifiedContent(); for (int i = shadows.size() - 1; i >= 0; i--) { shadow = shadows[i]; int shadowX = isHorizontal() ? shadow->x() : shadow->y(); int shadowY = isHorizontal() ? shadow->y() : -shadow->x(); FloatSize offset(shadowX, shadowY); drawLooper.addShadow(offset, shadow->blur(), shadow->color(), DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowIgnoresAlpha); } context->setDrawLooper(drawLooper); } // FIXME: Why is this always LTR? Fix by passing correct text run flags below. FloatPoint boxOrigin(paintOffset); boxOrigin.move(x(), y()); FloatRect boxRect(boxOrigin, LayoutSize(logicalWidth(), logicalHeight())); FloatPoint textOrigin(boxOrigin.x(), boxOrigin.y() + style->fontMetrics().ascent()); TextRun textRun = RenderBlock::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion); TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = boxRect; context->drawText(font, textRunPaintInfo, textOrigin); // Restore the regular fill color. if (styleTextColor != context->fillColor()) context->setFillColor(styleTextColor, style->colorSpace()); if (hasShadow) context->clearDrawLooper(); paintMarkupBox(paintInfo, paintOffset, lineTop, lineBottom, style); }
void DetailsMarkerPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (paintInfo.phase != PaintPhaseForeground || m_layoutDetailsMarker.style()->visibility() != VISIBLE) { BlockPainter(m_layoutDetailsMarker).paint(paintInfo, paintOffset); return; } if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutDetailsMarker, paintInfo.phase, paintOffset)) return; LayoutPoint boxOrigin(paintOffset + m_layoutDetailsMarker.location()); LayoutRect overflowRect(m_layoutDetailsMarker.visualOverflowRect()); overflowRect.moveBy(boxOrigin); if (!paintInfo.cullRect().intersectsCullRect(overflowRect)) return; LayoutObjectDrawingRecorder layoutDrawingRecorder(paintInfo.context, m_layoutDetailsMarker, paintInfo.phase, overflowRect, paintOffset); const Color color(m_layoutDetailsMarker.resolveColor(CSSPropertyColor)); paintInfo.context.setStrokeColor(color); paintInfo.context.setStrokeStyle(SolidStroke); paintInfo.context.setStrokeThickness(1.0f); paintInfo.context.setFillColor(color); boxOrigin.move(m_layoutDetailsMarker.borderLeft() + m_layoutDetailsMarker.paddingLeft(), m_layoutDetailsMarker.borderTop() + m_layoutDetailsMarker.paddingTop()); paintInfo.context.fillPath(getPath(boxOrigin)); }
void FaceVertexItem::transform(const Matrix4& matrix) { // Pick the translation components from the matrix and apply the translation Vector2 translation(matrix.tx(), matrix.ty()); // Get the translated texture position Vector2 newTexPosition = _windingVertex.texcoord + translation; // Construct the pivot Vector2 pivot; // Check if the pivot if (GlobalRegistry().get(ui::RKEY_FACE_VERTEX_SCALE_PIVOT_IS_CENTROID) == "1") { pivot = getTexCentroid(); } else { // Take the farthest point of the texture AABB as pivot AABB texAABB = getTexAABB(); Vector2 boxOrigin(texAABB.getOrigin().x(), texAABB.getOrigin().y()); Vector2 boxExtentsS(texAABB.getExtents().x(), 0); Vector2 boxExtentsT(0, texAABB.getExtents().y()); pivot = boxOrigin + boxExtentsS + boxExtentsT; pivot = getFurthestPivot(_windingVertex.texcoord, pivot, boxOrigin - boxExtentsS + boxExtentsT); pivot = getFurthestPivot(_windingVertex.texcoord, pivot, boxOrigin - boxExtentsS - boxExtentsT); pivot = getFurthestPivot(_windingVertex.texcoord, pivot, boxOrigin + boxExtentsS - boxExtentsT); } // Take the centroid as pivot Vector2 newDist = newTexPosition - pivot; Vector2 dist = _windingVertex.texcoord - pivot; // First, move the texture to the 0,0 origin in UV space // Second, apply the scale // Third, move the texture back to where it was, the pivot remains unchanged Vector3 pivotTranslation(pivot.x(), pivot.y(), 0); // Setup the matrices Matrix4 pivotToOrigin = Matrix4::getTranslation(-pivotTranslation); Matrix4 originToPivot = Matrix4::getTranslation(pivotTranslation); Matrix4 scale = Matrix4::getScale(Vector3(newDist.x()/dist.x(), newDist.y()/dist.y(), 0)); // Apply the matrices to the current texture transform, pre-multiplied in the correct order Matrix4 texTransform = _sourceFace.getTexdef().m_projection.getTransform(1.0, 1.0); // TODO: mattn - the parameters are wrong matrix4_premultiply_by_matrix4(texTransform, pivotToOrigin); matrix4_premultiply_by_matrix4(texTransform, scale); matrix4_premultiply_by_matrix4(texTransform, originToPivot); // Save it back to the face _sourceFace.getTexdef().m_projection.setTransform(1, 1, texTransform); _sourceFace.texdefChanged(); }
GLFont::Box GLFont::calcStringBox(GLsizei stringWidth) const { /* Calculate the string's scaled width: */ Vector boxSize(GLfloat(stringWidth-1)*textHeight/GLfloat(fontHeight-1),textHeight,0.0f); /* Calculate the string's bounding box origin: */ Vector boxOrigin(0.0f,0.0f,0.0f); switch(hAlignment) { case Left: boxOrigin[0]=0.0f; break; case Center: boxOrigin[0]=-0.5f*boxSize[0]; break; case Right: boxOrigin[0]=-boxSize[0]; break; } switch(vAlignment) { case Top: boxOrigin[1]=-boxSize[1]; break; case VCenter: boxOrigin[1]=-0.5f*boxSize[1]; break; case Baseline: boxOrigin[1]=-boxSize[1]*GLfloat(baseLine)/GLfloat(fontHeight); break; case Bottom: boxOrigin[1]=0.0f; break; } return Box(boxOrigin,boxSize); }
bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit, LayoutUnit) { // FIXME: integrate with InlineTextBox::nodeAtPoint better. ASSERT(!isLineBreak()); PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, request, renderer()->style()->pointerEvents()); bool isVisible = renderer()->style()->visibility() == VISIBLE; if (isVisible || !hitRules.requireVisible) { if ((hitRules.canHitStroke && (renderer()->style()->svgStyle()->hasStroke() || !hitRules.requireStroke)) || (hitRules.canHitFill && (renderer()->style()->svgStyle()->hasFill() || !hitRules.requireFill))) { FloatPoint boxOrigin(x(), y()); boxOrigin.moveBy(accumulatedOffset); FloatRect rect(boxOrigin, size()); if (rect.intersects(result.rectForPoint(pointInContainer))) { renderer()->updateHitTestResult(result, pointInContainer - toLayoutSize(accumulatedOffset)); if (!result.addNodeToRectBasedTestResult(renderer()->node(), pointInContainer, rect)) return true; } } } return false; }
bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit, LayoutUnit, HitTestAction) { // FIXME: integrate with InlineTextBox::nodeAtPoint better. ASSERT(!isLineBreak()); PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_TEXT_HITTESTING, request, renderer().style().pointerEvents()); bool isVisible = renderer().style().visibility() == VISIBLE; if (isVisible || !hitRules.requireVisible) { if ((hitRules.canHitStroke && (renderer().style().svgStyle().hasStroke() || !hitRules.requireStroke)) || (hitRules.canHitFill && (renderer().style().svgStyle().hasFill() || !hitRules.requireFill))) { FloatPoint boxOrigin(x(), y()); boxOrigin.moveBy(accumulatedOffset); FloatRect rect(boxOrigin, size()); if (locationInContainer.intersects(rect)) { float scalingFactor = renderer().scalingFactor(); ASSERT(scalingFactor); float baseline = renderer().scaledFont().fontMetrics().floatAscent() / scalingFactor; AffineTransform fragmentTransform; for (auto& fragment : m_textFragments) { FloatQuad fragmentQuad(FloatRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height)); fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) fragmentQuad = fragmentTransform.mapQuad(fragmentQuad); if (fragmentQuad.containsPoint(locationInContainer.point())) { renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); if (!result.addNodeToRectBasedTestResult(&renderer().textNode(), request, locationInContainer, rect)) return true; } } } } } return false; }
dgInt32 dgCollisionConvexPolygon::CalculateContactToConvexHullDescrete(dgCollisionParamProxy& proxy, const dgVector& polyInstanceScale, const dgVector& polyInstanceInvScale) { dgAssert(proxy.m_referenceCollision->IsType(dgCollision::dgCollisionConvexShape_RTTI)); dgAssert(proxy.m_floatingCollision->IsType(dgCollision::dgCollisionConvexPolygon_RTTI)); const dgCollisionInstance* const polygonInstance = proxy.m_floatingCollision; dgAssert(this == polygonInstance->GetChildShape()); dgAssert(m_count); dgAssert(m_count < dgInt32(sizeof (m_localPoly) / sizeof (m_localPoly[0]))); dgInt32 count = 0; m_normal = m_normal.CompProduct4(polyInstanceInvScale); dgAssert(m_normal.m_w == dgFloat32(0.0f)); m_normal = m_normal.CompProduct4(m_normal.DotProduct4(m_normal).InvSqrt()); dgVector savedFaceNormal(m_normal); dgVector savedPosit (proxy.m_matrix.m_posit); proxy.m_matrix.m_posit = dgVector::m_wOne; dgVector hullOrigin(proxy.m_matrix.UnrotateVector (savedPosit)); for (dgInt32 i = 0; i < m_count; i++) { m_localPoly[i] = hullOrigin + polyInstanceScale.CompProduct4(dgVector(&m_vertex[m_vertexIndex[i] * m_stride])); dgAssert(m_localPoly[i].m_w == dgFloat32(0.0f)); } dgContact* const contactJoint = proxy.m_contactJoint; const dgCollisionInstance* const hull = proxy.m_referenceCollision; dgVector normalInHull(proxy.m_matrix.RotateVector(m_normal)); dgVector pointInHull(hull->SupportVertex(normalInHull.Scale4(dgFloat32(-1.0f)), NULL)); dgVector p0(proxy.m_matrix.UntransformVector(pointInHull)); dgVector p1(proxy.m_matrix.UntransformVector(hull->SupportVertex(normalInHull, NULL))); dgFloat32 penetration = (m_localPoly[0] - p0) % m_normal + proxy.m_skinThickness; if (penetration < dgFloat32(0.0f)) { contactJoint->m_closestDistance = -penetration; proxy.m_matrix.m_posit = savedPosit; return 0; } contactJoint->m_closestDistance = dgFloat32(0.0f); dgFloat32 distance = (m_localPoly[0] - p1) % m_normal; if (distance >= dgFloat32(0.0f)) { proxy.m_matrix.m_posit = savedPosit; return 0; } dgVector boxSize (hull->GetBoxSize() & dgVector::m_triplexMask); dgVector boxOrigin ((hull->GetBoxOrigin() & dgVector::m_triplexMask) + dgVector::m_wOne); bool inside = true; dgInt32 i0 = m_count - 1; for (dgInt32 i = 0; i < m_count; i++) { dgVector e(m_localPoly[i] - m_localPoly[i0]); dgVector n(m_normal * e); //dgPlane plane(n, -(m_localPoly[i0] % n)); dgPlane plane(n, - m_localPoly[i0].DotProduct4 (n).GetScalar()); plane = proxy.m_matrix.TransformPlane(plane); //dgFloat32 supportDist = dgAbsf(plane.m_x) * boxSize.m_x + dgAbsf(plane.m_y) * boxSize.m_y + dgAbsf(plane.m_z) * boxSize.m_z; //dgFloat32 centerDist = plane.Evalue(boxOrigin); dgFloat32 supportDist = boxSize.DotProduct4 (plane.Abs()).GetScalar(); dgFloat32 centerDist = plane.DotProduct4 (boxOrigin).GetScalar(); if ((centerDist + supportDist) < dgFloat32(0.0f)) { proxy.m_matrix.m_posit = savedPosit; return 0; } if ((centerDist - supportDist) < dgFloat32(0.0f)) { inside = false; break; } i0 = i; } const dgInt32 hullId = hull->GetUserDataID(); if (inside & !proxy.m_intersectionTestOnly) { dgAssert(penetration >= dgFloat32(0.0f)); dgVector pointsContacts[64]; dgAssert(penetration >= 0.0f); dgVector point(pointInHull + normalInHull.Scale4(penetration)); count = hull->CalculatePlaneIntersection(normalInHull.Scale4(dgFloat32(-1.0f)), point, pointsContacts, 1.0f); dgVector step(normalInHull.Scale4((proxy.m_skinThickness - penetration) * dgFloat32(0.5f))); const dgMatrix& worldMatrix = hull->m_globalMatrix; dgContactPoint* const contactsOut = proxy.m_contacts; dgAssert(contactsOut); dgVector globalNormal(worldMatrix.RotateVector(normalInHull)); for (dgInt32 i = 0; i < count; i++) { contactsOut[i].m_point = worldMatrix.TransformVector(pointsContacts[i] + step); contactsOut[i].m_normal = globalNormal; contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; contactsOut[i].m_penetration = penetration; } } else { dgFloat32 convexSphapeUmbra = hull->GetUmbraClipSize(); if (m_faceClipSize > convexSphapeUmbra) { BeamClipping(dgVector(dgFloat32(0.0f)), convexSphapeUmbra); m_faceClipSize = hull->m_childShape->GetBoxMaxRadius(); } dgCollisionConvex* const convexShape = (dgCollisionConvex*)hull->m_childShape; count = convexShape->CalculateConvexToConvexContact(proxy); dgAssert(proxy.m_intersectionTestOnly || (count >= 0)); if (count >= 1) { dgContactPoint* const contactsOut = proxy.m_contacts; if (m_closestFeatureType == 3) { for (dgInt32 i = 0; i < count; i++) { //contactsOut[i].m_userId = m_faceId; contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; } } else { dgVector normal(polygonInstance->m_globalMatrix.UnrotateVector(contactsOut[0].m_normal)); if (normal.DotProduct4(savedFaceNormal).GetScalar() < dgFloat32(0.9995f)) { dgInt32 index = m_adjacentFaceEdgeNormalIndex[m_closestFeatureStartIndex]; dgVector n(&m_vertex[index * m_stride]); if ((savedFaceNormal.DotProduct4(n).GetScalar() > dgFloat32(0.9995f))) { normal = n; } else { dgVector dir0(n * savedFaceNormal); dgVector dir1(n * normal); dgFloat32 projection = dir0.DotProduct4(dir1).GetScalar(); if (projection <= dgFloat32(0.0f)) { normal = n; } } normal = polygonInstance->m_globalMatrix.RotateVector(normal); for (dgInt32 i = 0; i < count; i++) { contactsOut[i].m_normal = normal; //contactsOut[i].m_userId = m_faceId; contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; } } else { for (dgInt32 i = 0; i < count; i++) { //contactsOut[i].m_userId = m_faceId; contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; } } } } } proxy.m_matrix.m_posit = savedPosit; return count; }
dgInt32 dgCollisionConvexPolygon::CalculateContactToConvexHullContinue (dgCollisionParamProxy& proxy, const dgVector& polyInstanceScale, const dgVector& polyInstanceInvScale) { dgAssert (proxy.m_referenceCollision->IsType (dgCollision::dgCollisionConvexShape_RTTI)); dgAssert (proxy.m_floatingCollision->IsType (dgCollision::dgCollisionConvexPolygon_RTTI)); const dgCollisionInstance* const hull = proxy.m_referenceCollision; dgAssert (this == proxy.m_floatingCollision->GetChildShape()); dgAssert (m_count); dgAssert (m_count < dgInt32 (sizeof (m_localPoly) / sizeof (m_localPoly[0]))); const dgBody* const floatingBody = proxy.m_floatingBody; const dgBody* const referenceBody = proxy.m_referenceBody; dgContact* const contactJoint = proxy.m_contactJoint; contactJoint->m_closestDistance = dgFloat32 (1.0e10f); m_normal = m_normal.CompProduct4(polyInstanceInvScale); dgAssert (m_normal.m_w == dgFloat32 (0.0f)); m_normal = m_normal.CompProduct4(m_normal.DotProduct4(m_normal).InvSqrt()); const dgVector savedFaceNormal (m_normal); for (dgInt32 i = 0; i < m_count; i ++) { m_localPoly[i] = polyInstanceScale.CompProduct4(dgVector (&m_vertex[m_vertexIndex[i] * m_stride])); dgAssert (m_localPoly[i].m_w == dgFloat32 (0.0f)); } dgVector hullOrigin (proxy.m_matrix.UntransformVector(dgVector (dgFloat32 (0.0f)))); hullOrigin = (hullOrigin - m_normal.CompProduct4(m_normal.DotProduct4(hullOrigin - m_localPoly[0]))) | dgVector::m_wOne; dgMatrix polygonMatrix; polygonMatrix[0] = m_localPoly[1] - m_localPoly[0]; polygonMatrix[0] = polygonMatrix[0].CompProduct4 (polygonMatrix[0].InvMagSqrt()); polygonMatrix[1] = m_normal; polygonMatrix[2] = polygonMatrix[0] * m_normal; polygonMatrix[3] = hullOrigin; dgAssert (polygonMatrix.TestOrthogonal()); dgMatrix savedProxyMatrix (proxy.m_matrix); proxy.m_matrix = polygonMatrix * proxy.m_matrix; dgVector floatingVeloc (floatingBody->m_veloc); dgVector referenceVeloc (referenceBody->m_veloc); const dgMatrix& hullMatrix = hull->GetGlobalMatrix(); dgVector hullRelativeVeloc (hullMatrix.UnrotateVector(referenceVeloc - floatingVeloc)); dgVector polyRelativeVeloc (proxy.m_matrix.UnrotateVector (hullRelativeVeloc)); dgVector polyBoxP0 (dgFloat32 ( 1.0e15f)); dgVector polyBoxP1 (dgFloat32 (-1.0e15f)); m_normal = polygonMatrix.UnrotateVector(m_normal); if (m_normal.DotProduct4(polyRelativeVeloc).m_x >= 0.0f) { proxy.m_matrix = savedProxyMatrix; return 0; } for (dgInt32 i = 0; i < m_count; i ++) { m_localPoly[i] = polygonMatrix.UntransformVector(m_localPoly[i]); dgAssert (m_localPoly[i].m_w == dgFloat32 (0.0f)); polyBoxP0 = polyBoxP0.GetMin (m_localPoly[i]); polyBoxP1 = polyBoxP1.GetMax (m_localPoly[i]); } dgInt32 count = 0; dgVector hullBoxP0; dgVector hullBoxP1; hull->CalcAABB (proxy.m_matrix.Inverse(), hullBoxP0, hullBoxP1); dgVector minBox (polyBoxP0 - hullBoxP1); dgVector maxBox (polyBoxP1 - hullBoxP0); dgFastRayTest ray (dgVector (dgFloat32 (0.0f)), polyRelativeVeloc); dgFloat32 distance = ray.BoxIntersect(minBox, maxBox); if (distance < dgFloat32 (1.0f)) { dgVector boxSize ((hullBoxP1 - hullBoxP0).Scale4 (dgFloat32 (0.5f))); // dgVector boxOrigin ((hullBoxP1 + hullBoxP0).Scale4 (dgFloat32 (0.5f))); // boxOrigin += polyRelativeVeloc.Scale4 (distance); dgVector normalInHull (proxy.m_matrix.RotateVector (m_normal.Scale4 (dgFloat32 (-1.0f)))); dgVector pointInHull (hull->SupportVertex (normalInHull, NULL)); dgVector pointInPlane (proxy.m_matrix.UntransformVector (pointInHull)); dgFloat32 distToPlane = (m_localPoly[0] - pointInPlane) % m_normal; dgFloat32 timeToPlane = distToPlane / (polyRelativeVeloc % m_normal); dgVector boxOrigin (pointInPlane + polyRelativeVeloc.Scale4(timeToPlane)); bool inside = true; dgInt32 i0 = m_count - 1; for (dgInt32 i = 0; i < m_count; i ++) { dgVector e (m_localPoly[i] - m_localPoly[i0]); dgVector n (m_normal * e); dgPlane plane (n, - (m_localPoly[i0] % n)); dgVector supportDist (plane.Abs().DotProduct4 (boxSize)); dgFloat32 centerDist = plane.Evalue(boxOrigin); if ((centerDist + supportDist.m_x) < dgFloat32 (0.0f)) { proxy.m_matrix = savedProxyMatrix; return 0; } if ((centerDist - supportDist.m_x) < dgFloat32 (0.0f)) { inside = false; } i0 = i; } // for the time being for the minkousky contact calculation inside = false; const dgInt32 hullId = hull->GetUserDataID(); if (inside) { dgVector normalInHull (proxy.m_matrix.RotateVector (m_normal.Scale4 (dgFloat32 (-1.0f)))); dgVector pointInHull (hull->SupportVertex (normalInHull, NULL)); dgVector p0 (proxy.m_matrix.UntransformVector (pointInHull)); dgFloat32 timetoImpact = dgFloat32 (0.0f); //dgFloat32 closestDistance = dgFloat32 (0.0f); dgAssert (0); // dgFloat32 penetration = (m_localPoly[0] - p0) % m_normal + proxy.m_skinThickness + DG_IMPULSIVE_CONTACT_PENETRATION; dgFloat32 penetration = (m_localPoly[0] - p0) % m_normal + proxy.m_skinThickness; if (penetration < dgFloat32 (0.0f)) { timetoImpact = penetration / (polyRelativeVeloc % m_normal); dgAssert (timetoImpact >= dgFloat32 (0.0f)); // closestDistance = -penetration; } if (timetoImpact <= proxy.m_timestep) { dgVector pointsContacts[64]; contactJoint->m_closestDistance = penetration; dgAssert (0); // dgVector point (pointInHull - normalInHull.Scale4(DG_IMPULSIVE_CONTACT_PENETRATION)); dgVector point (pointInHull); count = hull->CalculatePlaneIntersection (normalInHull, point, pointsContacts, 1.0f); dgAssert (0); // dgVector step (hullRelativeVeloc.Scale3 (timetoImpact) + normalInHull.Scale4(DG_IMPULSIVE_CONTACT_PENETRATION)); dgVector step (hullRelativeVeloc.Scale3 (timetoImpact)); penetration = dgMax (penetration, dgFloat32 (0.0f)); const dgMatrix& worldMatrix = hull->m_globalMatrix; dgContactPoint* const contactsOut = proxy.m_contacts; dgVector globalNormal (worldMatrix.RotateVector(normalInHull)); for (dgInt32 i = 0; i < count; i ++) { contactsOut[i].m_point = worldMatrix.TransformVector (pointsContacts[i] + step); contactsOut[i].m_normal = globalNormal; contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; contactsOut[i].m_penetration = penetration; } } } else { dgFloat32 convexSphapeUmbra = hull->GetUmbraClipSize (); if (m_faceClipSize > convexSphapeUmbra) { BeamClipping (boxOrigin, convexSphapeUmbra); m_faceClipSize = hull->m_childShape->GetBoxMaxRadius(); } dgCollisionConvex* const convexShape = (dgCollisionConvex*) hull->m_childShape; count = convexShape->CalculateConvexCastContacts (proxy); // dgAssert (proxy.m_intersectionTestOnly || (count >= 0)); if (count >= 1) { dgContactPoint* const contactsOut = proxy.m_contacts; #if 0 if (m_closestFeatureType == 3) { for (dgInt32 i = 0; i < count; i ++) { contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; } } else { dgVector normal (polygonInstance->m_globalMatrix.UnrotateVector(contactsOut[0].m_normal)); if ((normal % savedFaceNormal) < dgFloat32 (0.995f)) { dgInt32 index = m_adjacentFaceEdgeNormalIndex[m_closestFeatureStartIndex]; dgVector n (&m_vertex[index * m_stride]); dgVector dir0 (n * savedFaceNormal); dgVector dir1 (n * normal); dgFloat32 projection = dir0 % dir1; if (projection <= dgFloat32 (0.0f)) { normal = n; } normal = polygonInstance->m_globalMatrix.RotateVector(normal); for (dgInt32 i = 0; i < count; i ++) { contactsOut[i].m_normal = normal; //contactsOut[i].m_userId = m_faceId; contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; } } else { for (dgInt32 i = 0; i < count; i ++) { //contactsOut[i].m_userId = m_faceId; contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; } } } #endif for (dgInt32 i = 0; i < count; i ++) { contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; } } } } proxy.m_matrix = savedProxyMatrix; return count; }
dgInt32 dgCollisionConvexPolygon::CalculateContactToConvexHullContinue(const dgWorld* const world, const dgCollisionInstance* const parentMesh, dgCollisionParamProxy& proxy) { dgAssert(proxy.m_instance0->IsType(dgCollision::dgCollisionConvexShape_RTTI)); dgAssert(proxy.m_instance1->IsType(dgCollision::dgCollisionConvexPolygon_RTTI)); dgAssert(this == proxy.m_instance1->GetChildShape()); dgAssert(m_count); dgAssert(m_count < dgInt32(sizeof (m_localPoly) / sizeof (m_localPoly[0]))); const dgBody* const body0 = proxy.m_body0; const dgBody* const body1 = proxy.m_body1; dgAssert (proxy.m_instance1->GetGlobalMatrix().TestIdentity()); dgVector relativeVelocity (body0->m_veloc - body1->m_veloc); if (m_normal.DotProduct4(relativeVelocity).GetScalar() >= 0.0f) { return 0; } dgFloat32 den = dgFloat32 (1.0f) / (relativeVelocity % m_normal); if (den > dgFloat32 (1.0e-5f)) { // this can actually happens dgAssert(0); return 0; } dgContact* const contactJoint = proxy.m_contactJoint; contactJoint->m_closestDistance = dgFloat32(1.0e10f); dgMatrix polygonMatrix; dgVector right (m_localPoly[1] - m_localPoly[0]); polygonMatrix[0] = right.CompProduct4(right.InvMagSqrt()); polygonMatrix[1] = m_normal; polygonMatrix[2] = polygonMatrix[0] * m_normal; polygonMatrix[3] = dgVector::m_wOne; dgAssert (polygonMatrix.TestOrthogonal()); dgVector polyBoxP0(dgFloat32(1.0e15f)); dgVector polyBoxP1(dgFloat32(-1.0e15f)); for (dgInt32 i = 0; i < m_count; i++) { dgVector point (polygonMatrix.UnrotateVector(m_localPoly[i])); polyBoxP0 = polyBoxP0.GetMin(point); polyBoxP1 = polyBoxP1.GetMax(point); } dgVector hullBoxP0; dgVector hullBoxP1; dgMatrix hullMatrix (polygonMatrix * proxy.m_instance0->m_globalMatrix); proxy.m_instance0->CalcAABB(hullMatrix, hullBoxP0, hullBoxP1); dgVector minBox(polyBoxP0 - hullBoxP1); dgVector maxBox(polyBoxP1 - hullBoxP0); dgVector veloc (polygonMatrix.UnrotateVector (relativeVelocity)); dgFastRayTest ray(dgVector(dgFloat32(0.0f)), veloc); dgFloat32 distance = ray.BoxIntersect(minBox, maxBox); dgInt32 count = 0; if (distance < dgFloat32(1.0f)) { bool inside = false; dgVector boxSize((hullBoxP1 - hullBoxP0).CompProduct4(dgVector::m_half)); dgVector sphereMag2 (boxSize.DotProduct4(boxSize)); boxSize = sphereMag2.Sqrt(); dgVector pointInPlane (polygonMatrix.RotateVector(hullBoxP1 + hullBoxP0).CompProduct4(dgVector::m_half)); dgFloat32 distToPlane = (m_localPoly[0] - pointInPlane) % m_normal; dgFloat32 timeToPlane0 = (distToPlane + boxSize.GetScalar()) * den; dgFloat32 timeToPlane1 = (distToPlane - boxSize.GetScalar()) * den; dgVector boxOrigin0 (pointInPlane + relativeVelocity.Scale4(timeToPlane0)); dgVector boxOrigin1 (pointInPlane + relativeVelocity.Scale4(timeToPlane1)); dgVector boxOrigin ((boxOrigin0 + boxOrigin1).CompProduct4(dgVector::m_half)); dgVector boxProjectSize (((boxOrigin0 - boxOrigin1).CompProduct4(dgVector::m_half))); sphereMag2 = boxProjectSize.DotProduct4(boxProjectSize); boxSize = sphereMag2.Sqrt(); dgAssert (boxOrigin.m_w == 0.0f); boxOrigin = boxOrigin | dgVector::m_wOne; if (!proxy.m_intersectionTestOnly) { inside = true; dgInt32 i0 = m_count - 1; for (dgInt32 i = 0; i < m_count; i++) { dgVector e(m_localPoly[i] - m_localPoly[i0]); dgVector n(m_normal * e & dgVector::m_triplexMask); dgFloat32 param = dgSqrt (sphereMag2.GetScalar() / (n.DotProduct4(n)).GetScalar()); dgPlane plane(n, -(m_localPoly[i0] % n)); dgVector p0 (boxOrigin + n.Scale4 (param)); dgVector p1 (boxOrigin - n.Scale4 (param)); dgFloat32 size0 = (plane.DotProduct4 (p0)).GetScalar(); dgFloat32 size1 = (plane.DotProduct4 (p1)).GetScalar(); if ((size0 < 0.0f) && (size1 < 0.0f)) { return 0; } if ((size0 * size1) < 0.0f) { inside = false; break; } i0 = i; } } dgFloat32 convexSphapeUmbra = dgMax (proxy.m_instance0->GetUmbraClipSize(), boxSize.GetScalar()); if (m_faceClipSize > convexSphapeUmbra) { BeamClipping(boxOrigin, convexSphapeUmbra); m_faceClipSize = proxy.m_instance0->m_childShape->GetBoxMaxRadius(); } const dgInt32 hullId = proxy.m_instance0->GetUserDataID(); if (inside & !proxy.m_intersectionTestOnly) { const dgMatrix& matrixInstance0 = proxy.m_instance0->m_globalMatrix; dgVector normalInHull(matrixInstance0.UnrotateVector(m_normal.Scale4(dgFloat32(-1.0f)))); dgVector pointInHull(proxy.m_instance0->SupportVertex(normalInHull, NULL)); dgVector p0 (matrixInstance0.TransformVector(pointInHull)); dgFloat32 timetoImpact = dgFloat32(0.0f); dgFloat32 penetration = (m_localPoly[0] - p0) % m_normal + proxy.m_skinThickness; if (penetration < dgFloat32(0.0f)) { timetoImpact = penetration / (relativeVelocity % m_normal); dgAssert(timetoImpact >= dgFloat32(0.0f)); } if (timetoImpact <= proxy.m_timestep) { dgVector contactPoints[64]; contactJoint->m_closestDistance = penetration; proxy.m_timestep = timetoImpact; proxy.m_normal = m_normal; proxy.m_closestPointBody0 = p0; proxy.m_closestPointBody1 = p0 + m_normal.Scale4(penetration); if (!proxy.m_intersectionTestOnly) { pointInHull -= normalInHull.Scale4 (DG_ROBUST_PLANE_CLIP); count = proxy.m_instance0->CalculatePlaneIntersection(normalInHull, pointInHull, contactPoints); dgVector step(relativeVelocity.Scale4(timetoImpact)); penetration = dgMax(penetration, dgFloat32(0.0f)); dgContactPoint* const contactsOut = proxy.m_contacts; for (dgInt32 i = 0; i < count; i++) { contactsOut[i].m_point = matrixInstance0.TransformVector(contactPoints[i]) + step; contactsOut[i].m_normal = m_normal; contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; contactsOut[i].m_penetration = penetration; } } } } else { m_vertexCount = dgUnsigned16 (m_count); count = world->CalculateConvexToConvexContacts(proxy); if (count >= 1) { dgContactPoint* const contactsOut = proxy.m_contacts; for (dgInt32 i = 0; i < count; i++) { contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; } } } } return count; }
dgInt32 dgCollisionConvexPolygon::CalculateContactToConvexHullDescrete(const dgWorld* const world, const dgCollisionInstance* const parentMesh, dgCollisionParamProxy& proxy) { dgInt32 count = 0; dgAssert(proxy.m_instance0->IsType(dgCollision::dgCollisionConvexShape_RTTI)); dgAssert(proxy.m_instance1->IsType(dgCollision::dgCollisionConvexPolygon_RTTI)); dgAssert (proxy.m_instance1->GetGlobalMatrix().TestIdentity()); const dgCollisionInstance* const polygonInstance = proxy.m_instance1; dgAssert(this == polygonInstance->GetChildShape()); dgAssert(m_count); dgAssert(m_count < dgInt32(sizeof (m_localPoly) / sizeof (m_localPoly[0]))); const dgMatrix& hullMatrix = proxy.m_instance0->m_globalMatrix; dgContact* const contactJoint = proxy.m_contactJoint; const dgCollisionInstance* const hull = proxy.m_instance0; dgVector normalInHull(hullMatrix.UnrotateVector(m_normal)); dgVector pointInHull(hull->SupportVertex(normalInHull.Scale4(dgFloat32(-1.0f)), NULL)); dgVector p0(hullMatrix.TransformVector(pointInHull)); dgFloat32 penetration = (m_localPoly[0] - p0) % m_normal + proxy.m_skinThickness; if (penetration < dgFloat32(0.0f)) { return 0; } dgVector p1(hullMatrix.TransformVector(hull->SupportVertex(normalInHull, NULL))); contactJoint->m_closestDistance = dgFloat32(0.0f); dgFloat32 distance = (m_localPoly[0] - p1) % m_normal; if (distance >= dgFloat32(0.0f)) { return 0; } dgVector boxSize (hull->GetBoxSize() & dgVector::m_triplexMask); dgVector boxOrigin ((hull->GetBoxOrigin() & dgVector::m_triplexMask) + dgVector::m_wOne); bool inside = true; dgInt32 i0 = m_count - 1; for (dgInt32 i = 0; i < m_count; i++) { dgVector e(m_localPoly[i] - m_localPoly[i0]); dgVector edgeBoundaryNormal(m_normal * e); dgPlane plane(edgeBoundaryNormal, - m_localPoly[i0].DotProduct4 (edgeBoundaryNormal).GetScalar()); plane = hullMatrix.TransformPlane(plane); dgFloat32 supportDist = boxSize.DotProduct4 (plane.Abs()).GetScalar(); dgFloat32 centerDist = plane.DotProduct4 (boxOrigin).GetScalar(); if ((centerDist + supportDist) < dgFloat32(0.0f)) { return 0; } if ((centerDist - supportDist) < dgFloat32(0.0f)) { inside = false; break; } i0 = i; } //inside = false; dgFloat32 convexSphapeUmbra = hull->GetUmbraClipSize(); if (m_faceClipSize > convexSphapeUmbra) { BeamClipping(dgVector(dgFloat32(0.0f)), convexSphapeUmbra); m_faceClipSize = hull->m_childShape->GetBoxMaxRadius(); } const dgInt32 hullId = hull->GetUserDataID(); if (inside & !proxy.m_intersectionTestOnly) { dgAssert(penetration >= dgFloat32(0.0f)); dgVector contactPoints[64]; dgAssert(penetration >= 0.0f); dgVector point(pointInHull + normalInHull.Scale4(penetration + DG_ROBUST_PLANE_CLIP)); count = hull->CalculatePlaneIntersection(normalInHull.Scale4(dgFloat32(-1.0f)), point, contactPoints); dgVector step(normalInHull.Scale4((proxy.m_skinThickness - penetration) * dgFloat32(0.5f))); dgContactPoint* const contactsOut = proxy.m_contacts; dgAssert(contactsOut); for (dgInt32 i = 0; i < count; i++) { contactsOut[i].m_point = hullMatrix.TransformVector(contactPoints[i] + step); contactsOut[i].m_normal = m_normal; contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; contactsOut[i].m_penetration = penetration; } } else { m_vertexCount = dgUnsigned16 (m_count); count = world->CalculateConvexToConvexContacts(proxy); dgAssert(proxy.m_intersectionTestOnly || (count >= 0)); if (count >= 1) { dgContactPoint* const contactsOut = proxy.m_contacts; if (m_closestFeatureType == 3) { for (dgInt32 i = 0; i < count; i++) { //contactsOut[i].m_userId = m_faceId; contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; } } else { dgVector normal (contactsOut[0].m_normal); if (normal.DotProduct4(m_normal).GetScalar() < dgFloat32(0.9995f)) { dgInt32 index = m_adjacentFaceEdgeNormalIndex[m_closestFeatureStartIndex]; dgVector adjacentNormal (CalculateGlobalNormal (parentMesh, dgVector(&m_vertex[index * m_stride]))); if ((m_normal.DotProduct4(adjacentNormal).GetScalar() > dgFloat32(0.9995f))) { normal = adjacentNormal; } else { dgVector dir0(adjacentNormal * m_normal); dgVector dir1(adjacentNormal * normal); dgFloat32 projection = dir0.DotProduct4(dir1).GetScalar(); if (projection <= dgFloat32(0.0f)) { normal = adjacentNormal; } } normal = polygonInstance->m_globalMatrix.RotateVector(normal); for (dgInt32 i = 0; i < count; i++) { contactsOut[i].m_normal = normal; contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; } } else { for (dgInt32 i = 0; i < count; i++) { contactsOut[i].m_shapeId0 = hullId; contactsOut[i].m_shapeId1 = m_faceId; } } } } } return count; }
void ListMarkerPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (paintInfo.phase != PaintPhaseForeground) return; if (m_layoutListMarker.style()->visibility() != VISIBLE) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.context, m_layoutListMarker, paintInfo.phase, paintOffset)) return; LayoutPoint boxOrigin(paintOffset + m_layoutListMarker.location()); LayoutRect overflowRect(m_layoutListMarker.visualOverflowRect()); if (m_layoutListMarker.selectionState() != SelectionNone) overflowRect.unite(m_layoutListMarker.localSelectionRect()); overflowRect.moveBy(boxOrigin); IntRect pixelSnappedOverflowRect = pixelSnappedIntRect(overflowRect); if (!paintInfo.rect.intersects(pixelSnappedOverflowRect)) return; LayoutObjectDrawingRecorder recorder(*paintInfo.context, m_layoutListMarker, paintInfo.phase, pixelSnappedOverflowRect, paintOffset); LayoutRect box(boxOrigin, m_layoutListMarker.size()); IntRect marker = m_layoutListMarker.getRelativeMarkerRect(); marker.moveBy(roundedIntPoint(boxOrigin)); GraphicsContext* context = paintInfo.context; if (m_layoutListMarker.isImage()) { context->drawImage(m_layoutListMarker.image()->image(&m_layoutListMarker, marker.size()).get(), marker); if (m_layoutListMarker.selectionState() != SelectionNone) { LayoutRect selRect = m_layoutListMarker.localSelectionRect(); selRect.moveBy(boxOrigin); context->fillRect(pixelSnappedIntRect(selRect), m_layoutListMarker.listItem()->selectionBackgroundColor()); } return; } if (m_layoutListMarker.selectionState() != SelectionNone) { LayoutRect selRect = m_layoutListMarker.localSelectionRect(); selRect.moveBy(boxOrigin); context->fillRect(pixelSnappedIntRect(selRect), m_layoutListMarker.listItem()->selectionBackgroundColor()); } const Color color(m_layoutListMarker.resolveColor(CSSPropertyColor)); context->setStrokeColor(color); context->setStrokeStyle(SolidStroke); context->setStrokeThickness(1.0f); context->setFillColor(color); EListStyleType type = m_layoutListMarker.style()->listStyleType(); switch (type) { case Disc: context->fillEllipse(marker); return; case Circle: context->strokeEllipse(marker); return; case Square: context->fillRect(marker); return; case NoneListStyle: return; case ArabicIndic: case Armenian: case Bengali: case Cambodian: case CJKIdeographic: case CjkEarthlyBranch: case CjkHeavenlyStem: case DecimalLeadingZero: case DecimalListStyle: case Devanagari: case EthiopicHalehame: case EthiopicHalehameAm: case EthiopicHalehameTiEr: case EthiopicHalehameTiEt: case Georgian: case Gujarati: case Gurmukhi: case Hebrew: case Hangul: case HangulConsonant: case KoreanHangulFormal: case KoreanHanjaFormal: case KoreanHanjaInformal: case Hiragana: case HiraganaIroha: case Kannada: case Katakana: case KatakanaIroha: case Khmer: case Lao: case LowerAlpha: case LowerArmenian: case LowerGreek: case LowerLatin: case LowerRoman: case Malayalam: case Mongolian: case Myanmar: case Oriya: case Persian: case SimpChineseFormal: case SimpChineseInformal: case Telugu: case Thai: case Tibetan: case TradChineseFormal: case TradChineseInformal: case UpperAlpha: case UpperArmenian: case UpperLatin: case UpperRoman: case Urdu: break; } if (m_layoutListMarker.text().isEmpty()) return; const Font& font = m_layoutListMarker.style()->font(); TextRun textRun = constructTextRun(font, m_layoutListMarker.text(), m_layoutListMarker.styleRef()); GraphicsContextStateSaver stateSaver(*context, false); if (!m_layoutListMarker.style()->isHorizontalWritingMode()) { marker.moveBy(roundedIntPoint(-boxOrigin)); marker = marker.transposedRect(); marker.moveBy(IntPoint(roundToInt(box.x()), roundToInt(box.y() - m_layoutListMarker.logicalHeight()))); stateSaver.save(); context->translate(marker.x(), marker.maxY()); context->rotate(static_cast<float>(deg2rad(90.))); context->translate(-marker.x(), -marker.maxY()); } TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = marker; IntPoint textOrigin = IntPoint(marker.x(), marker.y() + m_layoutListMarker.style()->fontMetrics().ascent()); // Text is not arbitrary. We can judge whether it's RTL from the first character, // and we only need to handle the direction RightToLeft for now. bool textNeedsReversing = WTF::Unicode::direction(m_layoutListMarker.text()[0]) == WTF::Unicode::RightToLeft; StringBuilder reversedText; if (textNeedsReversing) { unsigned length = m_layoutListMarker.text().length(); reversedText.reserveCapacity(length); for (int i = length - 1; i >= 0; --i) reversedText.append(m_layoutListMarker.text()[i]); ASSERT(reversedText.length() == length); textRun.setText(reversedText.toString()); } const UChar suffix = m_layoutListMarker.listMarkerSuffix(type, m_layoutListMarker.listItem()->value()); UChar suffixStr[2] = { m_layoutListMarker.style()->isLeftToRightDirection() ? suffix : static_cast<UChar>(' '), m_layoutListMarker.style()->isLeftToRightDirection() ? static_cast<UChar>(' ') : suffix }; TextRun suffixRun = constructTextRun(font, suffixStr, 2, m_layoutListMarker.styleRef(), m_layoutListMarker.style()->direction()); TextRunPaintInfo suffixRunInfo(suffixRun); suffixRunInfo.bounds = marker; if (m_layoutListMarker.style()->isLeftToRightDirection()) { context->drawText(font, textRunPaintInfo, textOrigin); context->drawText(font, suffixRunInfo, textOrigin + IntSize(font.width(textRun), 0)); } else { context->drawText(font, suffixRunInfo, textOrigin); context->drawText(font, textRunPaintInfo, textOrigin + IntSize(font.width(suffixRun), 0)); } }
void ListMarkerPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (paintInfo.phase != PaintPhaseForeground) return; if (m_layoutListMarker.style()->visibility() != EVisibility::Visible) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible( paintInfo.context, m_layoutListMarker, paintInfo.phase)) return; LayoutPoint boxOrigin(paintOffset + m_layoutListMarker.location()); LayoutRect overflowRect(m_layoutListMarker.visualOverflowRect()); overflowRect.moveBy(boxOrigin); IntRect pixelSnappedOverflowRect = pixelSnappedIntRect(overflowRect); if (!paintInfo.cullRect().intersectsCullRect(overflowRect)) return; LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutListMarker, paintInfo.phase, pixelSnappedOverflowRect); LayoutRect box(boxOrigin, m_layoutListMarker.size()); IntRect marker = m_layoutListMarker.getRelativeMarkerRect(); marker.moveBy(roundedIntPoint(boxOrigin)); GraphicsContext& context = paintInfo.context; if (m_layoutListMarker.isImage()) { context.drawImage(m_layoutListMarker.image() ->image(m_layoutListMarker, marker.size(), m_layoutListMarker.styleRef().effectiveZoom()) .get(), marker); if (m_layoutListMarker.getSelectionState() != SelectionNone) { LayoutRect selRect = m_layoutListMarker.localSelectionRect(); selRect.moveBy(boxOrigin); context.fillRect( pixelSnappedIntRect(selRect), m_layoutListMarker.listItem()->selectionBackgroundColor()); } return; } LayoutListMarker::ListStyleCategory styleCategory = m_layoutListMarker.getListStyleCategory(); if (styleCategory == LayoutListMarker::ListStyleCategory::None) return; Color color(m_layoutListMarker.resolveColor(CSSPropertyColor)); if (BoxPainter::shouldForceWhiteBackgroundForPrintEconomy( m_layoutListMarker.styleRef(), m_layoutListMarker.listItem()->document())) color = TextPainter::textColorForWhiteBackground(color); // Apply the color to the list marker text. context.setFillColor(color); const EListStyleType listStyle = m_layoutListMarker.style()->listStyleType(); if (styleCategory == LayoutListMarker::ListStyleCategory::Symbol) { paintSymbol(context, color, marker, listStyle); return; } if (m_layoutListMarker.text().isEmpty()) return; const Font& font = m_layoutListMarker.style()->font(); TextRun textRun = constructTextRun(font, m_layoutListMarker.text(), m_layoutListMarker.styleRef()); GraphicsContextStateSaver stateSaver(context, false); if (!m_layoutListMarker.style()->isHorizontalWritingMode()) { marker.moveBy(roundedIntPoint(-boxOrigin)); marker = marker.transposedRect(); marker.moveBy( IntPoint(roundToInt(box.x()), roundToInt(box.y() - m_layoutListMarker.logicalHeight()))); stateSaver.save(); context.translate(marker.x(), marker.maxY()); context.rotate(static_cast<float>(deg2rad(90.))); context.translate(-marker.x(), -marker.maxY()); } TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = marker; const SimpleFontData* fontData = m_layoutListMarker.style()->font().primaryFont(); IntPoint textOrigin = IntPoint( marker.x(), marker.y() + (fontData ? fontData->getFontMetrics().ascent() : 0)); // Text is not arbitrary. We can judge whether it's RTL from the first // character, and we only need to handle the direction RightToLeft for now. bool textNeedsReversing = WTF::Unicode::direction(m_layoutListMarker.text()[0]) == WTF::Unicode::RightToLeft; StringBuilder reversedText; if (textNeedsReversing) { unsigned length = m_layoutListMarker.text().length(); reversedText.reserveCapacity(length); for (int i = length - 1; i >= 0; --i) reversedText.append(m_layoutListMarker.text()[i]); DCHECK(reversedText.length() == length); textRun.setText(reversedText.toString()); } const UChar suffix = ListMarkerText::suffix(listStyle, m_layoutListMarker.listItem()->value()); UChar suffixStr[2] = {suffix, static_cast<UChar>(' ')}; TextRun suffixRun = constructTextRun(font, suffixStr, 2, m_layoutListMarker.styleRef(), m_layoutListMarker.style()->direction()); TextRunPaintInfo suffixRunInfo(suffixRun); suffixRunInfo.bounds = marker; if (m_layoutListMarker.style()->isLeftToRightDirection()) { context.drawText(font, textRunPaintInfo, textOrigin); context.drawText(font, suffixRunInfo, textOrigin + IntSize(font.width(textRun), 0)); } else { context.drawText(font, suffixRunInfo, textOrigin); context.drawText(font, textRunPaintInfo, textOrigin + IntSize(font.width(suffixRun), 0)); } }