NS_IMETHODIMP nsSVGPathGeometryFrame::UpdateCoveredRegion() { mRect.Empty(); gfxContext context(nsSVGUtils::GetThebesComputationalSurface()); GeneratePath(&context); context.IdentityMatrix(); gfxRect extent = context.GetUserPathExtent(); // Be careful when replacing the following logic to get the fill and stroke // extents independently (instead of computing the stroke extents from the // path extents). You may think that you can just use the stroke extents if // there is both a fill and a stroke. In reality it's necessary to calculate // both the fill and stroke extents, and take the union of the two. There are // two reasons for this: // // # Due to stroke dashing, in certain cases the fill extents could actually // extend outside the stroke extents. // # If the stroke is very thin, cairo won't paint any stroke, and so the // stroke bounds that it will return will be empty. if (HasStroke()) { SetupCairoStrokeGeometry(&context); if (extent.Width() <= 0 && extent.Height() <= 0) { // If 'extent' is empty, its position will not be set. Although // GetUserStrokeExtent gets the extents wrong we can still use it // to get the device space position of zero length stroked paths. extent = context.GetUserStrokeExtent(); extent.pos.x += extent.size.width / 2; extent.pos.y += extent.size.height / 2; extent.size.width = 0; extent.size.height = 0; } extent = nsSVGUtils::PathExtentsToMaxStrokeExtents(extent, this); } else if (GetStyleSVG()->mFill.mType == eStyleSVGPaintType_None) { extent = gfxRect(0, 0, 0, 0); } if (!extent.IsEmpty()) { mRect = nsSVGUtils::ToAppPixelRect(PresContext(), extent); } // Add in markers mRect = GetCoveredRegion(); return NS_OK; }
PRBool nsSVGGeometryFrame::SetupCairoStroke(gfxContext *aContext) { if (!HasStroke()) { return PR_FALSE; } SetupCairoStrokeHitGeometry(aContext); const nsStyleSVG* style = GetStyleSVG(); float opacity = MaybeOptimizeOpacity(style->mStrokeOpacity); nsSVGPaintServerFrame *ps = GetPaintServer(&style->mStroke, nsSVGEffects::StrokeProperty()); if (ps && ps->SetupPaintServer(aContext, this, opacity)) return PR_TRUE; // On failure, use the fallback colour in case we have an // objectBoundingBox where the width or height of the object is zero. // See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox SetupFallbackOrPaintColor(aContext, GetStyleContext(), &nsStyleSVG::mStroke, opacity); return PR_TRUE; }
/* ============================================== idSWFTextInstance::CalcMaxScroll ============================================== */ int idSWFTextInstance::CalcMaxScroll( int numLines ) { if ( numLines != -1 ) { if ( numLines < 0 ) { numLines = 0; } maxscroll = numLines; return maxscroll; } const idSWFEditText * shape = editText; if ( !( shape->flags & SWF_ET_MULTILINE ) ) { return 0; } if ( swf == NULL ) { return 0; } idSWFDictionaryEntry * fontEntry = swf->FindDictionaryEntry( shape->fontID, SWF_DICT_FONT ); if ( fontEntry == NULL ) { return 0; } idSWFFont * swfFont = fontEntry->font; if ( swfFont == NULL ) { return 0; } const idFont * fontInfo = swfFont->fontID; if ( fontInfo == NULL ) { return 0; } idStr textCheck; if ( variable.IsEmpty() ) { textCheck = idLocalization::GetString( text ); } else { textCheck = idLocalization::GetString( variable ); } if ( textCheck.IsEmpty() ) { return 0; } float x = bounds.tl.x; float y = bounds.tl.y; idList< idStr > textLines; idStr * currentLine = &textLines.Alloc(); // tracks the last breakable character we found int lastbreak = 0; float lastbreakX = 0; int charIndex = 0; if ( IsSubtitle() ) { charIndex = GetSubStartIndex(); } while ( charIndex < textCheck.Length() ) { if ( textCheck[ charIndex ] == '\n' ) { if ( shape->flags & SWF_ET_MULTILINE ) { currentLine->Append( '\n' ); x = bounds.tl.x; y += linespacing; currentLine = &textLines.Alloc(); lastbreak = 0; charIndex++; continue; } else { break; } } int glyphStart = charIndex; uint32 tc = textCheck.UTF8Char( charIndex ); scaledGlyphInfo_t glyph; fontInfo->GetScaledGlyph( glyphScale, tc, glyph ); float glyphSkip = glyph.xSkip; if ( HasStroke() ) { glyphSkip += ( swf_textStrokeSizeGlyphSpacer.GetFloat() * GetStrokeWeight() * glyphScale ); } if ( x + glyphSkip > bounds.br.x ) { if ( shape->flags & ( SWF_ET_MULTILINE | SWF_ET_WORDWRAP ) ) { if ( lastbreak > 0 ) { int curLineIndex = currentLine - &textLines[0]; idStr * newline = &textLines.Alloc(); currentLine = &textLines[ curLineIndex ]; if ( maxLines == 1 ) { currentLine->CapLength( currentLine->Length() - 3 ); currentLine->Append( "..." ); break; } else { *newline = currentLine->c_str() + lastbreak; currentLine->CapLength( lastbreak ); currentLine = newline; x -= lastbreakX; } } else { currentLine = &textLines.Alloc(); x = bounds.tl.x; } lastbreak = 0; } else { break; } } while ( glyphStart < charIndex && glyphStart < text.Length() ) { currentLine->Append( text[ glyphStart++ ] ); } x += glyphSkip; if ( tc == ' ' || tc == '-' ) { lastbreak = currentLine->Length(); lastbreakX = x; } } maxscroll = textLines.Num() - maxLines; if ( maxscroll < 0 ) { maxscroll = 0; } return maxscroll; }
gfxRect nsSVGPathGeometryFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, PRUint32 aFlags) { if (aToBBoxUserspace.IsSingular()) { // XXX ReportToConsole return gfxRect(0.0, 0.0, 0.0, 0.0); } nsRefPtr<gfxContext> context = new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface()); GeneratePath(context, &aToBBoxUserspace); context->IdentityMatrix(); gfxRect bbox; // Be careful when replacing the following logic to get the fill and stroke // extents independently (instead of computing the stroke extents from the // path extents). You may think that you can just use the stroke extents if // there is both a fill and a stroke. In reality it's necessary to calculate // both the fill and stroke extents, and take the union of the two. There are // two reasons for this: // // # Due to stroke dashing, in certain cases the fill extents could actually // extend outside the stroke extents. // # If the stroke is very thin, cairo won't paint any stroke, and so the // stroke bounds that it will return will be empty. gfxRect pathExtents = context->GetUserPathExtent(); // Account for fill: if ((aFlags & nsSVGUtils::eBBoxIncludeFill) != 0 && ((aFlags & nsSVGUtils::eBBoxIgnoreFillIfNone) == 0 || GetStyleSVG()->mFill.mType != eStyleSVGPaintType_None)) { bbox = pathExtents; } // Account for stroke: if ((aFlags & nsSVGUtils::eBBoxIncludeStroke) != 0 && ((aFlags & nsSVGUtils::eBBoxIgnoreStrokeIfNone) == 0 || HasStroke())) { // We can't use context->GetUserStrokeExtent() since it doesn't work for // device space extents. Instead we approximate the stroke extents from // pathExtents using PathExtentsToMaxStrokeExtents. if (pathExtents.Width() <= 0 && pathExtents.Height() <= 0) { // We have a zero length path, but it may still have non-empty stroke // bounds depending on the value of stroke-linecap. We need to fix up // pathExtents before it can be used with PathExtentsToMaxStrokeExtents // though, because if pathExtents is empty, its position will not have // been set. Happily we can use context->GetUserStrokeExtent() to find // the center point of the extents even though it gets the extents wrong. SetupCairoStrokeGeometry(context); pathExtents.MoveTo(context->GetUserStrokeExtent().Center()); pathExtents.SizeTo(0, 0); } bbox = bbox.Union(nsSVGUtils::PathExtentsToMaxStrokeExtents(pathExtents, this, aToBBoxUserspace)); } // Account for markers: if ((aFlags & nsSVGUtils::eBBoxIncludeMarkers) != 0 && static_cast<nsSVGPathGeometryElement*>(mContent)->IsMarkable()) { float strokeWidth = GetStrokeWidth(); MarkerProperties properties = GetMarkerProperties(this); if (properties.MarkersExist()) { nsTArray<nsSVGMark> marks; static_cast<nsSVGPathGeometryElement*>(mContent)->GetMarkPoints(&marks); PRUint32 num = marks.Length(); if (num) { nsSVGMarkerFrame *frame = properties.GetMarkerStartFrame(); if (frame) { gfxRect mbbox = frame->GetMarkBBoxContribution(aToBBoxUserspace, aFlags, this, &marks[0], strokeWidth); bbox.UnionRect(bbox, mbbox); } frame = properties.GetMarkerMidFrame(); if (frame) { for (PRUint32 i = 1; i < num - 1; i++) { gfxRect mbbox = frame->GetMarkBBoxContribution(aToBBoxUserspace, aFlags, this, &marks[i], strokeWidth); bbox.UnionRect(bbox, mbbox); } } frame = properties.GetMarkerEndFrame(); if (frame) { gfxRect mbbox = frame->GetMarkBBoxContribution(aToBBoxUserspace, aFlags, this, &marks[num-1], strokeWidth); bbox.UnionRect(bbox, mbbox); } } } } return bbox; }