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;
}
Beispiel #3
0
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));
}
Beispiel #5
0
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();
}
Beispiel #6
0
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));
    }
}
Beispiel #14
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));
  }
}