diff --git a/configure.in b/configure.in index 8e098b0557..a56257cc9b 100644 --- a/configure.in +++ b/configure.in @@ -6452,6 +6452,35 @@ then if test "x$ac_cv_sqlite_enable_unlock_notify" = "xno"; then AC_MSG_ERROR([System SQLite library is not compiled with SQLITE_ENABLE_UNLOCK_NOTIFY.]) fi + + dnl ========================================= + dnl === SQLITE_ENABLE_DBSTAT_VTAB check === + dnl ========================================= + dnl check to see if the system SQLite package is compiled with + dnl SQLITE_ENABLE_DBSTAT_VTAB. + AC_MSG_CHECKING(for SQLITE_ENABLE_DBSTAT_VTAB support in system SQLite) + _SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $SQLITE_CFLAGS" + _SAVE_LIBS="$LIBS" + LIBS="$LIBS $SQLITE_LIBS" + AC_CACHE_VAL(ac_cv_sqlite_dbstat_vtab,[ + AC_TRY_RUN([ + #include "sqlite3.h" + + int main(int argc, char **argv){ + return !sqlite3_compileoption_used("SQLITE_ENABLE_DBSTAT_VTAB"); + }], + ac_cv_sqlite_dbstat_vtab=yes, + ac_cv_sqlite_dbstat_vtab=no, + ac_cv_sqlite_dbstat_vtab=no + ) + ]) + AC_MSG_RESULT($ac_cv_sqlite_dbstat_vtab) + CFLAGS="$_SAVE_CFLAGS" + LIBS="$_SAVE_LIBS" + if test "x$ac_cv_sqlite_dbstat_vtab" = "xno"; then + AC_MSG_ERROR([System SQLite library is not compiled with SQLITE_ENABLE_DBSTAT_VTAB.]) + fi fi if test -n "$MOZ_NATIVE_SQLITE"; then diff --git a/db/sqlite3/src/moz.build b/db/sqlite3/src/moz.build index cc00d3341b..0961988d1f 100644 --- a/db/sqlite3/src/moz.build +++ b/db/sqlite3/src/moz.build @@ -37,7 +37,8 @@ SOURCES += [ # concurrent connections, especially when they use shared cache. # Note: Be sure to update the configure.in checks when these change! for var in ('SQLITE_SECURE_DELETE', 'SQLITE_THREADSAFE', 'SQLITE_CORE', - 'SQLITE_ENABLE_FTS3', 'SQLITE_ENABLE_UNLOCK_NOTIFY'): + 'SQLITE_ENABLE_FTS3', 'SQLITE_ENABLE_UNLOCK_NOTIFY', + 'SQLITE_ENABLE_DBSTAT_VTAB'): DEFINES[var] = 1 DEFINES['SQLITE_DEFAULT_PAGE_SIZE'] = 32768 diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index f9010aaf04..c0b46a520d 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -152,8 +152,6 @@ using namespace mozilla::image; using namespace mozilla::ipc; using namespace mozilla::layers; -namespace mgfx = mozilla::gfx; - namespace mozilla { namespace dom { @@ -297,10 +295,10 @@ public: AdjustedTargetForFilter(CanvasRenderingContext2D *ctx, DrawTarget *aFinalTarget, - const mgfx::IntPoint& aFilterSpaceToTargetOffset, - const mgfx::IntRect& aPreFilterBounds, - const mgfx::IntRect& aPostFilterBounds, - mgfx::CompositionOp aCompositionOp) + const gfx::IntPoint& aFilterSpaceToTargetOffset, + const gfx::IntRect& aPreFilterBounds, + const gfx::IntRect& aPostFilterBounds, + gfx::CompositionOp aCompositionOp) : mCtx(nullptr) , mCompositionOp(aCompositionOp) { @@ -348,7 +346,7 @@ public: // Return a SourceSurface that contains the FillPaint or StrokePaint source. already_AddRefed - DoSourcePaint(mgfx::IntRect& aRect, CanvasRenderingContext2D::Style aStyle) + DoSourcePaint(gfx::IntRect& aRect, CanvasRenderingContext2D::Style aStyle) { if (aRect.IsEmpty()) { return nullptr; @@ -367,8 +365,8 @@ public: dt->SetTransform(transform); if (transform.Invert()) { - mgfx::Rect dtBounds(0, 0, aRect.width, aRect.height); - mgfx::Rect fillRect = transform.TransformBounds(dtBounds); + gfx::Rect dtBounds(0, 0, aRect.width, aRect.height); + gfx::Rect fillRect = transform.TransformBounds(dtBounds); dt->FillRect(fillRect, CanvasGeneralPattern().ForStyle(mCtx, aStyle, dt)); } return dt->Snapshot(); @@ -390,9 +388,9 @@ public: AutoRestoreTransform autoRestoreTransform(mFinalTarget); mFinalTarget->SetTransform(Matrix()); - mgfx::FilterSupport::RenderFilterDescription( + gfx::FilterSupport::RenderFilterDescription( mFinalTarget, mCtx->CurrentState().filter, - mgfx::Rect(mPostFilterBounds), + gfx::Rect(mPostFilterBounds), snapshot, mSourceGraphicRect, fillPaint, mFillPaintRect, strokePaint, mStrokePaintRect, @@ -410,12 +408,12 @@ private: RefPtr mTarget; RefPtr mFinalTarget; CanvasRenderingContext2D *mCtx; - mgfx::IntRect mSourceGraphicRect; - mgfx::IntRect mFillPaintRect; - mgfx::IntRect mStrokePaintRect; - mgfx::IntRect mPostFilterBounds; - mgfx::IntPoint mOffset; - mgfx::CompositionOp mCompositionOp; + gfx::IntRect mSourceGraphicRect; + gfx::IntRect mFillPaintRect; + gfx::IntRect mStrokePaintRect; + gfx::IntRect mPostFilterBounds; + gfx::IntPoint mOffset; + gfx::CompositionOp mCompositionOp; }; /* This is an RAII based class that can be used as a drawtarget for @@ -429,8 +427,8 @@ public: AdjustedTargetForShadow(CanvasRenderingContext2D *ctx, DrawTarget *aFinalTarget, - const mgfx::Rect& aBounds, - mgfx::CompositionOp aCompositionOp) + const gfx::Rect& aBounds, + gfx::CompositionOp aCompositionOp) : mCtx(nullptr) , mCompositionOp(aCompositionOp) { @@ -441,7 +439,7 @@ public: mSigma = state.ShadowBlurSigma(); - mgfx::Rect bounds = aBounds; + gfx::Rect bounds = aBounds; int32_t blurRadius = state.ShadowBlurRadius(); @@ -488,7 +486,7 @@ public: return mTarget; } - mgfx::IntPoint OffsetToFinalDT() + gfx::IntPoint OffsetToFinalDT() { return mTempRect.TopLeft(); } @@ -498,8 +496,8 @@ private: RefPtr mFinalTarget; CanvasRenderingContext2D *mCtx; Float mSigma; - mgfx::IntRect mTempRect; - mgfx::CompositionOp mCompositionOp; + gfx::IntRect mTempRect; + gfx::CompositionOp mCompositionOp; }; /* This is an RAII based class that can be used as a drawtarget for @@ -519,7 +517,7 @@ public: typedef CanvasRenderingContext2D::ContextState ContextState; explicit AdjustedTarget(CanvasRenderingContext2D* ctx, - const mgfx::Rect *aBounds = nullptr) + const gfx::Rect *aBounds = nullptr) { mTarget = ctx->mTarget; @@ -529,21 +527,21 @@ public: // calculate what their maximum required bounds would need to be if we // were to fill the whole canvas. Everything outside those bounds we don't // need to render. - mgfx::Rect r(0, 0, ctx->mWidth, ctx->mHeight); - mgfx::Rect maxSourceNeededBoundsForShadow = + gfx::Rect r(0, 0, ctx->mWidth, ctx->mHeight); + gfx::Rect maxSourceNeededBoundsForShadow = MaxSourceNeededBoundsForShadow(r, ctx); - mgfx::Rect maxSourceNeededBoundsForFilter = + gfx::Rect maxSourceNeededBoundsForFilter = MaxSourceNeededBoundsForFilter(maxSourceNeededBoundsForShadow, ctx); - mgfx::Rect bounds = maxSourceNeededBoundsForFilter; + gfx::Rect bounds = maxSourceNeededBoundsForFilter; if (aBounds) { bounds = bounds.Intersect(*aBounds); } - mgfx::Rect boundsAfterFilter = BoundsAfterFilter(bounds, ctx); + gfx::Rect boundsAfterFilter = BoundsAfterFilter(bounds, ctx); mozilla::gfx::CompositionOp op = ctx->CurrentState().op; - mgfx::IntPoint offsetToFinalDT; + gfx::IntPoint offsetToFinalDT; // First set up the shadow draw target, because the shadow goes outside. // It applies to the post-filter results, if both a filter and a shadow @@ -556,20 +554,20 @@ public: // If we also have a filter, the filter needs to be drawn with OP_OVER // because shadow drawing already applies op on the result. - op = mgfx::CompositionOp::OP_OVER; + op = gfx::CompositionOp::OP_OVER; } // Now set up the filter draw target. if (ctx->NeedToApplyFilter()) { bounds.RoundOut(); - mgfx::IntRect intBounds; + gfx::IntRect intBounds; if (!bounds.ToIntRect(&intBounds)) { return; } mFilterTarget = MakeUnique( ctx, mTarget, offsetToFinalDT, intBounds, - mgfx::RoundedToInt(boundsAfterFilter), op); + gfx::RoundedToInt(boundsAfterFilter), op); mTarget = mFilterTarget->DT(); } } @@ -594,8 +592,8 @@ public: private: - mgfx::Rect - MaxSourceNeededBoundsForFilter(const mgfx::Rect& aDestBounds, CanvasRenderingContext2D *ctx) + gfx::Rect + MaxSourceNeededBoundsForFilter(const gfx::Rect& aDestBounds, CanvasRenderingContext2D *ctx) { if (!ctx->NeedToApplyFilter()) { return aDestBounds; @@ -606,21 +604,21 @@ private: nsIntRegion strokePaintNeededRegion; FilterSupport::ComputeSourceNeededRegions( - ctx->CurrentState().filter, mgfx::RoundedToInt(aDestBounds), + ctx->CurrentState().filter, gfx::RoundedToInt(aDestBounds), sourceGraphicNeededRegion, fillPaintNeededRegion, strokePaintNeededRegion); - return mgfx::Rect(sourceGraphicNeededRegion.GetBounds()); + return gfx::Rect(sourceGraphicNeededRegion.GetBounds()); } - mgfx::Rect - MaxSourceNeededBoundsForShadow(const mgfx::Rect& aDestBounds, CanvasRenderingContext2D *ctx) + gfx::Rect + MaxSourceNeededBoundsForShadow(const gfx::Rect& aDestBounds, CanvasRenderingContext2D *ctx) { if (!ctx->NeedToDrawShadow()) { return aDestBounds; } const ContextState &state = ctx->CurrentState(); - mgfx::Rect sourceBounds = aDestBounds - state.shadowOffset; + gfx::Rect sourceBounds = aDestBounds - state.shadowOffset; sourceBounds.Inflate(state.ShadowBlurRadius()); // Union the shadow source with the original rect because we're going to @@ -628,25 +626,25 @@ private: return sourceBounds.Union(aDestBounds); } - mgfx::Rect - BoundsAfterFilter(const mgfx::Rect& aBounds, CanvasRenderingContext2D *ctx) + gfx::Rect + BoundsAfterFilter(const gfx::Rect& aBounds, CanvasRenderingContext2D *ctx) { if (!ctx->NeedToApplyFilter()) { return aBounds; } - mgfx::Rect bounds(aBounds); + gfx::Rect bounds(aBounds); bounds.RoundOut(); - mgfx::IntRect intBounds; + gfx::IntRect intBounds; if (!bounds.ToIntRect(&intBounds)) { - return mgfx::Rect(); + return gfx::Rect(); } nsIntRegion extents = - mgfx::FilterSupport::ComputePostFilterExtents(ctx->CurrentState().filter, - intBounds); - return mgfx::Rect(extents.GetBounds()); + gfx::FilterSupport::ComputePostFilterExtents(ctx->CurrentState().filter, + intBounds); + return gfx::Rect(extents.GetBounds()); } RefPtr mTarget; @@ -676,7 +674,9 @@ CanvasGradient::AddColorStop(float offset, const nsAString& colorstr, ErrorResul } nscolor color; - if (!nsRuleNode::ComputeColor(value, nullptr, nullptr, color)) { + nsCOMPtr presShell = mContext ? mContext->GetPresShell() : nullptr; + if (!nsRuleNode::ComputeColor(value, presShell ? presShell->GetPresContext() : nullptr, + nullptr, color)) { rv.Throw(NS_ERROR_DOM_SYNTAX_ERR); return; } @@ -948,6 +948,7 @@ CanvasRenderingContext2D::CanvasRenderingContext2D() , mZero(false), mOpaque(false) , mResetLayer(true) , mIPC(false) + , mIsSkiaGL(false) , mDrawObserver(nullptr) , mIsEntireFrameInvalid(false) , mPredictManyRedrawCalls(false) @@ -1137,7 +1138,7 @@ CanvasRenderingContext2D::Redraw() } void -CanvasRenderingContext2D::Redraw(const mgfx::Rect &r) +CanvasRenderingContext2D::Redraw(const gfx::Rect &r) { mIsCapturedFrameInvalid = true; @@ -1185,8 +1186,7 @@ CanvasRenderingContext2D::RedrawUser(const gfxRect& r) return; } - mgfx::Rect newr = - mTarget->GetTransform().TransformBounds(ToRect(r)); + gfx::Rect newr = mTarget->GetTransform().TransformBounds(ToRect(r)); Redraw(newr); } @@ -1233,7 +1233,7 @@ bool CanvasRenderingContext2D::SwitchRenderingMode(RenderingMode aRenderingMode) mRenderingMode = attemptedMode; // Restore the content from the old DrawTarget - mgfx::Rect r(0, 0, mWidth, mHeight); + gfx::Rect r(0, 0, mWidth, mHeight); mTarget->DrawSurface(snapshot, r, r); // Restore the clips and transform @@ -1378,6 +1378,8 @@ CanvasRenderingContext2D::EnsureTarget(RenderingMode aRenderingMode) } } + mIsSkiaGL = false; + // Check that the dimensions are sane IntSize size(mWidth, mHeight); if (size.width <= gfxPrefs::MaxCanvasSize() && @@ -1411,6 +1413,7 @@ CanvasRenderingContext2D::EnsureTarget(RenderingMode aRenderingMode) if (mTarget) { AddDemotableContext(this); mBufferProvider = new PersistentBufferProviderBasic(mTarget); + mIsSkiaGL = true; } else { printf_stderr("Failed to create a SkiaGL DrawTarget, falling back to software\n"); mode = RenderingMode::SoftwareBackendMode; @@ -1445,15 +1448,15 @@ CanvasRenderingContext2D::EnsureTarget(RenderingMode aRenderingMode) JS_updateMallocCounter(context, mWidth * mHeight * 4); } - mTarget->ClearRect(mgfx::Rect(Point(0, 0), Size(mWidth, mHeight))); - if (mTarget->GetBackendType() == mgfx::BackendType::CAIRO) { + mTarget->ClearRect(gfx::Rect(Point(0, 0), Size(mWidth, mHeight))); + if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) { // Cairo doesn't play well with huge clips. When given a very big clip it // will try to allocate big mask surface without taking the target // size into account which can cause OOM. See bug 1034593. // This limits the clip extents to the size of the canvas. // A fix in Cairo would probably be preferable, but requires somewhat // invasive changes. - mTarget->PushClipRect(mgfx::Rect(Point(0, 0), Size(mWidth, mHeight))); + mTarget->PushClipRect(gfx::Rect(Point(0, 0), Size(mWidth, mHeight))); } // Force a full layer transaction since we didn't have a layer before // and now we might need one. @@ -1578,9 +1581,9 @@ CanvasRenderingContext2D::InitializeWithSurface(nsIDocShell *shell, mTarget = sErrorTarget; } - if (mTarget->GetBackendType() == mgfx::BackendType::CAIRO) { + if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) { // Cf comment in EnsureTarget - mTarget->PushClipRect(mgfx::Rect(Point(0, 0), Size(mWidth, mHeight))); + mTarget->PushClipRect(gfx::Rect(Point(0, 0), Size(mWidth, mHeight))); } return NS_OK; @@ -2540,7 +2543,7 @@ CanvasRenderingContext2D::ClearRect(double x, double y, double w, return; } - mTarget->ClearRect(mgfx::Rect(x, y, w, h)); + mTarget->ClearRect(gfx::Rect(x, y, w, h)); RedrawUser(gfxRect(x, y, w, h)); } @@ -2601,16 +2604,16 @@ CanvasRenderingContext2D::FillRect(double x, double y, double w, } } - mgfx::Rect bounds; + gfx::Rect bounds; EnsureTarget(); if (NeedToCalculateBounds()) { - bounds = mgfx::Rect(x, y, w, h); + bounds = gfx::Rect(x, y, w, h); bounds = mTarget->GetTransform().TransformBounds(bounds); } AdjustedTarget(this, bounds.IsEmpty() ? nullptr : &bounds)-> - FillRect(mgfx::Rect(x, y, w, h), + FillRect(gfx::Rect(x, y, w, h), CanvasGeneralPattern().ForStyle(this, Style::FILL, mTarget), DrawOptions(state.globalAlpha, UsedOperation())); @@ -2623,7 +2626,7 @@ CanvasRenderingContext2D::StrokeRect(double x, double y, double w, { const ContextState &state = CurrentState(); - mgfx::Rect bounds; + gfx::Rect bounds; if (!w && !h) { return; @@ -2639,8 +2642,8 @@ CanvasRenderingContext2D::StrokeRect(double x, double y, double w, } if (NeedToCalculateBounds()) { - bounds = mgfx::Rect(x - state.lineWidth / 2.0f, y - state.lineWidth / 2.0f, - w + state.lineWidth, h + state.lineWidth); + bounds = gfx::Rect(x - state.lineWidth / 2.0f, y - state.lineWidth / 2.0f, + w + state.lineWidth, h + state.lineWidth); bounds = mTarget->GetTransform().TransformBounds(bounds); } @@ -2679,14 +2682,14 @@ CanvasRenderingContext2D::StrokeRect(double x, double y, double w, } AdjustedTarget(this, bounds.IsEmpty() ? nullptr : &bounds)-> - StrokeRect(mgfx::Rect(x, y, w, h), - CanvasGeneralPattern().ForStyle(this, Style::STROKE, mTarget), - StrokeOptions(state.lineWidth, state.lineJoin, - state.lineCap, state.miterLimit, - state.dash.Length(), - state.dash.Elements(), - state.dashOffset), - DrawOptions(state.globalAlpha, UsedOperation())); + StrokeRect(gfx::Rect(x, y, w, h), + CanvasGeneralPattern().ForStyle(this, Style::STROKE, mTarget), + StrokeOptions(state.lineWidth, state.lineJoin, + state.lineCap, state.miterLimit, + state.dash.Length(), + state.dash.Elements(), + state.dashOffset), + DrawOptions(state.globalAlpha, UsedOperation())); Redraw(); } @@ -2707,14 +2710,13 @@ CanvasRenderingContext2D::BeginPath() void CanvasRenderingContext2D::Fill(const CanvasWindingRule& winding) { - EnsureTarget(); EnsureUserSpacePath(winding); if (!mPath) { return; } - mgfx::Rect bounds; + gfx::Rect bounds; if (NeedToCalculateBounds()) { bounds = mPath->GetBounds(mTarget->GetTransform()); @@ -2737,7 +2739,7 @@ void CanvasRenderingContext2D::Fill(const CanvasPath& path, const CanvasWindingR return; } - mgfx::Rect bounds; + gfx::Rect bounds; if (NeedToCalculateBounds()) { bounds = gfxpath->GetBounds(mTarget->GetTransform()); @@ -2753,7 +2755,6 @@ void CanvasRenderingContext2D::Fill(const CanvasPath& path, const CanvasWindingR void CanvasRenderingContext2D::Stroke() { - EnsureTarget(); EnsureUserSpacePath(); if (!mPath) { @@ -2767,7 +2768,7 @@ CanvasRenderingContext2D::Stroke() state.dash.Length(), state.dash.Elements(), state.dashOffset); - mgfx::Rect bounds; + gfx::Rect bounds; if (NeedToCalculateBounds()) { bounds = mPath->GetStrokedBounds(strokeOptions, mTarget->GetTransform()); @@ -2798,7 +2799,7 @@ CanvasRenderingContext2D::Stroke(const CanvasPath& path) state.dash.Length(), state.dash.Elements(), state.dashOffset); - mgfx::Rect bounds; + gfx::Rect bounds; if (NeedToCalculateBounds()) { bounds = gfxpath->GetStrokedBounds(strokeOptions, mTarget->GetTransform()); @@ -2889,8 +2890,6 @@ bool CanvasRenderingContext2D::DrawCustomFocusRing(mozilla::dom::Element& aEleme void CanvasRenderingContext2D::Clip(const CanvasWindingRule& winding) { - EnsureTarget(); - EnsureUserSpacePath(winding); if (!mPath) { @@ -3048,6 +3047,8 @@ CanvasRenderingContext2D::Ellipse(double aX, double aY, double aRadiusX, double void CanvasRenderingContext2D::EnsureWritablePath() { + EnsureTarget(); + if (mDSPathBuilder) { return; } @@ -3066,7 +3067,6 @@ CanvasRenderingContext2D::EnsureWritablePath() return; } - EnsureTarget(); if (!mPath) { NS_ASSERTION(!mPathTransformWillUpdate, "mPathTransformWillUpdate should be false, if all paths are null"); mPathBuilder = mTarget->CreatePathBuilder(fillRule); @@ -3087,8 +3087,9 @@ CanvasRenderingContext2D::EnsureUserSpacePath(const CanvasWindingRule& winding) if(winding == CanvasWindingRule::Evenodd) fillRule = FillRule::FILL_EVEN_ODD; + EnsureTarget(); + if (!mPath && !mPathBuilder && !mDSPathBuilder) { - EnsureTarget(); mPathBuilder = mTarget->CreatePathBuilder(fillRule); } @@ -3364,6 +3365,7 @@ CanvasRenderingContext2D::AddHitRegion(const HitRegionOptions& options, ErrorRes { RefPtr path; if (options.mPath) { + EnsureTarget(); path = options.mPath->GetPath(CanvasWindingRule::Nonzero, mTarget); } @@ -3379,7 +3381,7 @@ CanvasRenderingContext2D::AddHitRegion(const HitRegionOptions& options, ErrorRes } // get the bounds of the current path. They are relative to the canvas - mgfx::Rect bounds(path->GetBounds(mTarget->GetTransform())); + gfx::Rect bounds(path->GetBounds(mTarget->GetTransform())); if ((bounds.width == 0) || (bounds.height == 0) || !bounds.IsFinite()) { // The specified region has no pixels. error.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); @@ -3443,7 +3445,7 @@ CanvasRenderingContext2D::GetHitRegionRect(Element* aElement, nsRect& aRect) for (unsigned int x = 0; x < mHitRegionsOptions.Length(); x++) { RegionInfo& info = mHitRegionsOptions[x]; if (info.mElement == aElement) { - mgfx::Rect bounds(info.mPath->GetBounds()); + gfx::Rect bounds(info.mPath->GetBounds()); gfxRect rect(bounds.x, bounds.y, bounds.width, bounds.height); aRect = nsLayoutUtils::RoundGfxRectToAppRect(rect, AppUnitsPerCSSPixel()); @@ -3707,12 +3709,18 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess buffer.mGlyphs = &glyphBuf.front(); buffer.mNumGlyphs = 1; const ContextState& state = *mState; - AdjustedTarget target(mCtx, &bounds); + const StrokeOptions strokeOpts(state.lineWidth, state.lineJoin, state.lineCap, state.miterLimit, state.dash.Length(), state.dash.Elements(), state.dashOffset); + + // We need to adjust the bounds for the adjusted target + bounds.Inflate(MaxStrokeExtents(strokeOpts, mCtx->mTarget->GetTransform())); + + AdjustedTarget target(mCtx, &bounds); + CanvasGeneralPattern cgp; const Pattern& patForStyle (cgp.ForStyle(mCtx, CanvasRenderingContext2D::Style::STROKE, mCtx->mTarget)); @@ -4289,11 +4297,11 @@ bool CanvasRenderingContext2D::IsPointInStroke(const CanvasPath& mPath, double x // On entry, aSourceRect is relative to aSurface, and on return aSourceRect is // relative to the returned surface. static already_AddRefed -ExtractSubrect(SourceSurface* aSurface, mgfx::Rect* aSourceRect, DrawTarget* aTargetDT) +ExtractSubrect(SourceSurface* aSurface, gfx::Rect* aSourceRect, DrawTarget* aTargetDT) { - mgfx::Rect roundedOutSourceRect = *aSourceRect; + gfx::Rect roundedOutSourceRect = *aSourceRect; roundedOutSourceRect.RoundOut(); - mgfx::IntRect roundedOutSourceRectInt; + gfx::IntRect roundedOutSourceRectInt; if (!roundedOutSourceRect.ToIntRect(&roundedOutSourceRectInt)) { RefPtr surface(aSurface); return surface.forget(); @@ -4617,19 +4625,19 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& image, Filter filter; if (CurrentState().imageSmoothingEnabled) - filter = mgfx::Filter::LINEAR; + filter = gfx::Filter::LINEAR; else - filter = mgfx::Filter::POINT; + filter = gfx::Filter::POINT; - mgfx::Rect bounds; + gfx::Rect bounds; if (NeedToCalculateBounds()) { - bounds = mgfx::Rect(dx, dy, dw, dh); + bounds = gfx::Rect(dx, dy, dw, dh); bounds = mTarget->GetTransform().TransformBounds(bounds); } if (srcSurf) { - mgfx::Rect sourceRect(sx, sy, sw, sh); + gfx::Rect sourceRect(sx, sy, sw, sh); if (element == mCanvasElement) { // srcSurf is a snapshot of mTarget. If we draw to mTarget now, we'll // trigger a COW copy of the whole canvas into srcSurf. That's a huge @@ -4640,14 +4648,14 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& image, } AdjustedTarget(this, bounds.IsEmpty() ? nullptr : &bounds)-> DrawSurface(srcSurf, - mgfx::Rect(dx, dy, dw, dh), + gfx::Rect(dx, dy, dw, dh), sourceRect, DrawSurfaceOptions(filter), DrawOptions(CurrentState().globalAlpha, UsedOperation())); } else { DrawDirectlyToCanvas(drawInfo, &bounds, - mgfx::Rect(dx, dy, dw, dh), - mgfx::Rect(sx, sy, sw, sh), + gfx::Rect(dx, dy, dw, dh), + gfx::Rect(sx, sy, sw, sh), imgSize); } @@ -4657,9 +4665,9 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& image, void CanvasRenderingContext2D::DrawDirectlyToCanvas( const nsLayoutUtils::DirectDrawInfo& image, - mgfx::Rect* bounds, - mgfx::Rect dest, - mgfx::Rect src, + gfx::Rect* bounds, + gfx::Rect dest, + gfx::Rect src, gfx::IntSize imgSize) { MOZ_ASSERT(src.width > 0 && src.height > 0, @@ -4925,10 +4933,10 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x, return; } - mgfx::Rect destRect(0, 0, w, h); - mgfx::Rect sourceRect(0, 0, sw, sh); + gfx::Rect destRect(0, 0, w, h); + gfx::Rect sourceRect(0, 0, sw, sh); mTarget->DrawSurface(source, destRect, sourceRect, - DrawSurfaceOptions(mgfx::Filter::POINT), + DrawSurfaceOptions(gfx::Filter::POINT), DrawOptions(GlobalAlpha(), CompositionOp::OP_OVER, AntialiasMode::NONE)); mTarget->Flush(); @@ -5066,9 +5074,9 @@ CanvasRenderingContext2D::DrawWidgetAsOnScreen(nsGlobalWindow& aWindow, return; } - mgfx::Rect sourceRect(mgfx::Point(0, 0), mgfx::Size(snapshot->GetSize())); + gfx::Rect sourceRect(gfx::Point(0, 0), gfx::Size(snapshot->GetSize())); mTarget->DrawSurface(snapshot, sourceRect, sourceRect, - DrawSurfaceOptions(mgfx::Filter::POINT), + DrawSurfaceOptions(gfx::Filter::POINT), DrawOptions(GlobalAlpha(), CompositionOp::OP_OVER, AntialiasMode::NONE)); mTarget->Flush(); @@ -5201,21 +5209,6 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx, return NS_ERROR_DOM_SYNTAX_ERR; } - IntRect srcRect(0, 0, mWidth, mHeight); - IntRect destRect(aX, aY, aWidth, aHeight); - IntRect srcReadRect = srcRect.Intersect(destRect); - RefPtr readback; - DataSourceSurface::MappedSurface rawData; - if (!srcReadRect.IsEmpty() && !mZero) { - RefPtr snapshot = mTarget->Snapshot(); - if (snapshot) { - readback = snapshot->GetDataSurface(); - } - if (!readback || !readback->Map(DataSourceSurface::READ, &rawData)) { - return NS_ERROR_OUT_OF_MEMORY; - } - } - JS::Rooted darray(aCx, JS_NewUint8ClampedArray(aCx, len.value())); if (!darray) { return NS_ERROR_OUT_OF_MEMORY; @@ -5226,6 +5219,21 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx, return NS_OK; } + IntRect srcRect(0, 0, mWidth, mHeight); + IntRect destRect(aX, aY, aWidth, aHeight); + IntRect srcReadRect = srcRect.Intersect(destRect); + RefPtr readback; + DataSourceSurface::MappedSurface rawData; + if (!srcReadRect.IsEmpty()) { + RefPtr snapshot = mTarget->Snapshot(); + if (snapshot) { + readback = snapshot->GetDataSurface(); + } + if (!readback || !readback->Map(DataSourceSurface::READ, &rawData)) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + IntRect dstWriteRect = srcReadRect; dstWriteRect.MoveBy(-aX, -aY); @@ -5244,10 +5252,6 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx, srcStride = aWidth * 4; } - // NOTE! dst is the same as src, and this relies on reading - // from src and advancing that ptr before writing to dst. - // NOTE! I'm not sure that it is, I think this comment might have been - // inherited from Thebes canvas and is no longer true uint8_t* dst = data + dstWriteRect.y * (aWidth * 4) + dstWriteRect.x * 4; uint8_t a,r,g,b; @@ -5518,7 +5522,7 @@ CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w dirtyRect.width, dirtyRect.height), IntPoint(dirtyRect.x, dirtyRect.y)); - Redraw(mgfx::Rect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height)); + Redraw(gfx::Rect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height)); return NS_OK; } @@ -5618,9 +5622,11 @@ CanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder, CanvasLayer *aOldLayer, LayerManager *aManager) { - if (mOpaque) { + if (mOpaque || mIsSkiaGL) { // If we're opaque then make sure we have a surface so we paint black // instead of transparent. + // If we're using SkiaGL, then SkiaGLTex() below needs the target to + // be accessible. EnsureTarget(); } diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index 311086a6f3..ca98fe3c13 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -723,6 +723,9 @@ protected: bool mResetLayer; // This is needed for drawing in drawAsyncXULElement bool mIPC; + // True if the current DrawTarget is using skia-gl, used so we can avoid + // requesting the DT from mBufferProvider to check. + bool mIsSkiaGL; nsTArray mUserDatas; diff --git a/dom/canvas/WebGLContextExtensions.cpp b/dom/canvas/WebGLContextExtensions.cpp index bf62beabe7..c620e6beef 100644 --- a/dom/canvas/WebGLContextExtensions.cpp +++ b/dom/canvas/WebGLContextExtensions.cpp @@ -159,6 +159,20 @@ WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const return gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_dxt1) && gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt3) && gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt5); + + case WebGLExtensionID::WEBGL_debug_renderer_info: + { + bool isEnabled = true; + +#ifdef RELEASE_BUILD + // Keep this disabled on Release and Beta for now. (see bug 1171228) + isEnabled = false; +#endif + if (Preferences::GetBool("webgl.disable-debug-renderer-info", false)) + isEnabled = false; + + return isEnabled; + } case WebGLExtensionID::WEBGL_depth_texture: // WEBGL_depth_texture supports DEPTH_STENCIL textures if (!gl->IsSupported(gl::GLFeature::packed_depth_stencil)) diff --git a/dom/canvas/WebGLContextState.cpp b/dom/canvas/WebGLContextState.cpp index 72e0d820e8..952ae107c8 100644 --- a/dom/canvas/WebGLContextState.cpp +++ b/dom/canvas/WebGLContextState.cpp @@ -4,16 +4,19 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "WebGLContext.h" -#include "WebGLContextUtils.h" -#include "WebGLBuffer.h" -#include "WebGLShader.h" -#include "WebGLProgram.h" -#include "WebGLFramebuffer.h" -#include "WebGLRenderbuffer.h" -#include "WebGLTexture.h" -#include "WebGLVertexArray.h" + #include "GLContext.h" #include "mozilla/dom/ToJSValue.h" +#include "mozilla/Preferences.h" +#include "nsString.h" +#include "WebGLBuffer.h" +#include "WebGLContextUtils.h" +#include "WebGLFramebuffer.h" +#include "WebGLProgram.h" +#include "WebGLRenderbuffer.h" +#include "WebGLShader.h" +#include "WebGLTexture.h" +#include "WebGLVertexArray.h" namespace mozilla { @@ -57,6 +60,18 @@ WebGLContext::Enable(GLenum cap) gl->fEnable(cap); } +static JS::Value +StringValue(JSContext* cx, const nsAString& str, ErrorResult& rv) +{ + JSString* jsStr = JS_NewUCStringCopyN(cx, str.BeginReading(), str.Length()); + if (!jsStr) { + rv.Throw(NS_ERROR_OUT_OF_MEMORY); + return JS::NullValue(); + } + + return JS::StringValue(jsStr); +} + bool WebGLContext::GetStencilBits(GLint* out_stencilBits) { @@ -176,19 +191,47 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv) } } - // Privileged string params exposed by WEBGL_debug_renderer_info: + // Privileged string params exposed by WEBGL_debug_renderer_info. + // The privilege check is done in WebGLContext::IsExtensionSupported. + // So here we just have to check that the extension is enabled. if (IsExtensionEnabled(WebGLExtensionID::WEBGL_debug_renderer_info)) { switch (pname) { case UNMASKED_VENDOR_WEBGL: case UNMASKED_RENDERER_WEBGL: - GLenum glstringname = LOCAL_GL_NONE; - if (pname == UNMASKED_VENDOR_WEBGL) { - glstringname = LOCAL_GL_VENDOR; - } else if (pname == UNMASKED_RENDERER_WEBGL) { - glstringname = LOCAL_GL_RENDERER; + { + const char* overridePref = nullptr; + GLenum driverEnum = LOCAL_GL_NONE; + + switch (pname) { + case UNMASKED_RENDERER_WEBGL: + overridePref = "webgl.renderer-string-override"; + driverEnum = LOCAL_GL_RENDERER; + break; + case UNMASKED_VENDOR_WEBGL: + overridePref = "webgl.vendor-string-override"; + driverEnum = LOCAL_GL_VENDOR; + break; + default: + MOZ_CRASH("bad `pname`"); + } + + bool hasRetVal = false; + + nsAutoString ret; + if (overridePref) { + nsresult res = Preferences::GetString(overridePref, &ret); + if (NS_SUCCEEDED(res) && ret.Length() > 0) + hasRetVal = true; + } + + if (!hasRetVal) { + const char* chars = reinterpret_cast(gl->fGetString(driverEnum)); + ret = NS_ConvertASCIItoUTF16(chars); + hasRetVal = true; + } + + return StringValue(cx, ret, rv); } - const GLchar* string = (const GLchar*) gl->fGetString(glstringname); - return StringValue(cx, string, rv); } } diff --git a/dom/canvas/crashtests/1183363.html b/dom/canvas/crashtests/1183363.html new file mode 100644 index 0000000000..2044a80928 --- /dev/null +++ b/dom/canvas/crashtests/1183363.html @@ -0,0 +1,23 @@ + + + + + + + + + + diff --git a/dom/canvas/crashtests/crashtests.list b/dom/canvas/crashtests/crashtests.list index 509e66194e..5f52a9ca3c 100644 --- a/dom/canvas/crashtests/crashtests.list +++ b/dom/canvas/crashtests/crashtests.list @@ -22,3 +22,4 @@ load 896047-2.html load 916128-1.html load 934939-1.html load 1099143-1.html +load 1183363.html diff --git a/dom/canvas/test/chrome/nonchrome_webgl_debug_renderer_info.html b/dom/canvas/test/chrome/nonchrome_webgl_debug_renderer_info.html index dfff63d15e..3af79906ee 100644 --- a/dom/canvas/test/chrome/nonchrome_webgl_debug_renderer_info.html +++ b/dom/canvas/test/chrome/nonchrome_webgl_debug_renderer_info.html @@ -2,6 +2,12 @@ - \ No newline at end of file + diff --git a/dom/canvas/test/chrome/test_webgl_debug_renderer_info.html b/dom/canvas/test/chrome/test_webgl_debug_renderer_info.html index 46fabe54f7..045a886ca3 100644 --- a/dom/canvas/test/chrome/test_webgl_debug_renderer_info.html +++ b/dom/canvas/test/chrome/test_webgl_debug_renderer_info.html @@ -43,13 +43,13 @@ function checkChromeCase(canvas) { var exts = gl.getSupportedExtensions(); ok(exts.indexOf("WEBGL_debug_renderer_info") != -1, "WEBGL_debug_renderer_info should be listed by getSupportedExtensions in chrome contexts"); - var debugRendererInfoExtension = gl.getExtension("WEBGL_debug_renderer_info"); - ok(debugRendererInfoExtension, + var ext = gl.getExtension("WEBGL_debug_renderer_info"); + ok(ext, "WEBGL_debug_renderer_info should be available through getExtension in chrome contexts"); - ok(debugRendererInfoExtension.UNMASKED_VENDOR_WEBGL == UNMASKED_VENDOR_WEBGL, + ok(ext.UNMASKED_VENDOR_WEBGL == UNMASKED_VENDOR_WEBGL, "UNMASKED_VENDOR_WEBGL has the correct value"); - ok(debugRendererInfoExtension.UNMASKED_RENDERER_WEBGL == UNMASKED_RENDERER_WEBGL, + ok(ext.UNMASKED_RENDERER_WEBGL == UNMASKED_RENDERER_WEBGL, "UNMASKED_RENDERER_WEBGL has the correct value"); ok(isNonEmptyString(gl.getParameter(UNMASKED_VENDOR_WEBGL)) && gl.getError() == gl.NO_ERROR, @@ -67,7 +67,7 @@ function main() // Now run the non-chrome code to verify the security of this WebGL chrome-only extension. var iframe = document.createElement("iframe"); - iframe.src = "http://mochi.test:8888/chrome/dom/canvas/test/chrome/nonchrome_webgl_debug_renderer_info.html"; + iframe.src = "chrome://mochitests/content/chrome/dom/canvas/test/chrome/nonchrome_webgl_debug_renderer_info.html"; iframe.onload = function () { diff --git a/dom/canvas/test/mochitest.ini b/dom/canvas/test/mochitest.ini index 48b4b743db..62926a4972 100644 --- a/dom/canvas/test/mochitest.ini +++ b/dom/canvas/test/mochitest.ini @@ -213,6 +213,7 @@ skip-if = toolkit != 'cocoa' [test_2d.path.rect.zero.6.html] disabled = bug 407107 [test_2d.strokeRect.zero.5.html] +[test_bug232227.html] [test_bug613794.html] [test_bug753758.html] [test_bug764125.html] diff --git a/dom/canvas/test/reftest/1177726-text-stroke-bounds-ref.html b/dom/canvas/test/reftest/1177726-text-stroke-bounds-ref.html new file mode 100644 index 0000000000..46d37d8ed8 --- /dev/null +++ b/dom/canvas/test/reftest/1177726-text-stroke-bounds-ref.html @@ -0,0 +1,24 @@ + + + + + Testcase for bug 1177726 + + + + +

No canvas.

+
+ + + + diff --git a/dom/canvas/test/reftest/1177726-text-stroke-bounds.html b/dom/canvas/test/reftest/1177726-text-stroke-bounds.html new file mode 100644 index 0000000000..1f459ce0b6 --- /dev/null +++ b/dom/canvas/test/reftest/1177726-text-stroke-bounds.html @@ -0,0 +1,28 @@ + + + + + Testcase for bug 1177726 + + + + +

No canvas.

+
+ + + + diff --git a/dom/canvas/test/reftest/reftest.list b/dom/canvas/test/reftest/reftest.list index 9a9d9d6a5c..37e4ad05d7 100644 --- a/dom/canvas/test/reftest/reftest.list +++ b/dom/canvas/test/reftest/reftest.list @@ -157,4 +157,6 @@ pref(canvas.focusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion pref(canvas.customfocusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion<15,8,500) skip-if(winWidget) needs-focus == drawCustomFocusRing.html drawCustomFocusRing-ref.html # Check that captureStream() displays in a local video element -pref(canvas.capturestream.enabled,true) fails-if(B2G) skip-if(winWidget&&layersGPUAccelerated&&d2d) == capturestream.html wrapper.html?green.png +pref(canvas.capturestream.enabled,true) skip-if(winWidget&&layersGPUAccelerated&&d2d) == capturestream.html wrapper.html?green.png + +fuzzy-if(Android,3,40) == 1177726-text-stroke-bounds.html 1177726-text-stroke-bounds-ref.html diff --git a/dom/canvas/test/test_bug232227.html b/dom/canvas/test/test_bug232227.html new file mode 100644 index 0000000000..da4c0e0151 --- /dev/null +++ b/dom/canvas/test/test_bug232227.html @@ -0,0 +1,151 @@ + + + + + Test for Bug 232227 + + + + +Mozilla Bug 232227 + + + + + + diff --git a/dom/canvas/test/webgl-mochitest.ini b/dom/canvas/test/webgl-mochitest.ini index 03e29d29a0..f93d980426 100644 --- a/dom/canvas/test/webgl-mochitest.ini +++ b/dom/canvas/test/webgl-mochitest.ini @@ -22,6 +22,7 @@ skip-if = (os == 'b2g') || buildapp == 'mulet' # Mulet - bug 1093639 (crashes in skip-if = android_version == '10' || android_version == '18' #Android 2.3 and 4.3 aws only; bug 1030942 [webgl-mochitest/test_noprog_draw.html] [webgl-mochitest/test_privileged_exts.html] +[webgl-mochitest/test_renderer_strings.html] [webgl-mochitest/test_texsubimage_float.html] [webgl-mochitest/test_webgl_available.html] skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests diff --git a/dom/canvas/test/webgl-mochitest/test_privileged_exts.html b/dom/canvas/test/webgl-mochitest/test_privileged_exts.html index 936b4d5658..c7895bcdf2 100644 --- a/dom/canvas/test/webgl-mochitest/test_privileged_exts.html +++ b/dom/canvas/test/webgl-mochitest/test_privileged_exts.html @@ -24,7 +24,7 @@ function TestExt(gl, name) { } // Privileged extensions: - TestExt(gl, 'WEBGL_debug_renderer_info'); + TestExt(gl, 'WEBGL_debug_shaders'); })(); diff --git a/dom/canvas/test/webgl-mochitest/test_renderer_strings.html b/dom/canvas/test/webgl-mochitest/test_renderer_strings.html new file mode 100644 index 0000000000..f41e58ee72 --- /dev/null +++ b/dom/canvas/test/webgl-mochitest/test_renderer_strings.html @@ -0,0 +1,98 @@ + + + + + + + + + + diff --git a/gfx/2d/Matrix.cpp b/gfx/2d/Matrix.cpp index c2c2fbf5fc..d7059e4d0b 100644 --- a/gfx/2d/Matrix.cpp +++ b/gfx/2d/Matrix.cpp @@ -91,8 +91,8 @@ Matrix::Rotation(Float aAngle) { Matrix newMatrix; - Float s = sin(aAngle); - Float c = cos(aAngle); + Float s = sinf(aAngle); + Float c = cosf(aAngle); newMatrix._11 = c; newMatrix._12 = s; diff --git a/gfx/2d/PathD2D.cpp b/gfx/2d/PathD2D.cpp index e442d113a0..2032862dc7 100644 --- a/gfx/2d/PathD2D.cpp +++ b/gfx/2d/PathD2D.cpp @@ -267,8 +267,8 @@ PathBuilderD2D::Arc(const Point &aOrigin, Float aRadius, Float aStartAngle, } Point endPoint; - endPoint.x = aOrigin.x + aRadius * cos(aEndAngle); - endPoint.y = aOrigin.y + aRadius * sin(aEndAngle); + endPoint.x = aOrigin.x + aRadius * cosf(aEndAngle); + endPoint.y = aOrigin.y + aRadius * sinf(aEndAngle); D2D1_ARC_SIZE arcSize = D2D1_ARC_SIZE_SMALL; D2D1_SWEEP_DIRECTION direction = @@ -296,8 +296,8 @@ PathBuilderD2D::Arc(const Point &aOrigin, Float aRadius, Float aStartAngle, else { // draw small circles as two half-circles Point midPoint; - midPoint.x = aOrigin.x + aRadius * cos(midAngle); - midPoint.y = aOrigin.y + aRadius * sin(midAngle); + midPoint.x = aOrigin.x + aRadius * cosf(midAngle); + midPoint.y = aOrigin.y + aRadius * sinf(midAngle); mSink->AddArc(D2D1::ArcSegment(D2DPoint(midPoint), D2D1::SizeF(aRadius, aRadius), diff --git a/gfx/2d/image_operations.h b/gfx/2d/image_operations.h index 2744e2c67f..8e31913632 100644 --- a/gfx/2d/image_operations.h +++ b/gfx/2d/image_operations.h @@ -185,8 +185,8 @@ inline float EvalLanczos(int filter_size, float x) { x < std::numeric_limits::epsilon()) return 1.0f; // Special case the discontinuity at the origin. float xpi = x * static_cast(M_PI); - return (sin(xpi) / xpi) * // sinc(x) - sin(xpi / filter_size) / (xpi / filter_size); // sinc(x/filter_size) + return (sinf(xpi) / xpi) * // sinc(x) + sinf(xpi / filter_size) / (xpi / filter_size); // sinc(x/filter_size) } // Evaluates the Hamming filter of the given filter size window for the given @@ -212,8 +212,8 @@ inline float EvalHamming(int filter_size, float x) { return 1.0f; // Special case the sinc discontinuity at the origin. const float xpi = x * static_cast(M_PI); - return ((sin(xpi) / xpi) * // sinc(x) - (0.54f + 0.46f * cos(xpi / filter_size))); // hamming(x) + return ((sinf(xpi) / xpi) * // sinc(x) + (0.54f + 0.46f * cosf(xpi / filter_size))); // hamming(x) } // ResizeFilter ---------------------------------------------------------------- diff --git a/gfx/gl/EGLUtils.cpp b/gfx/gl/EGLUtils.cpp index e87458bfba..bc55d7fb03 100644 --- a/gfx/gl/EGLUtils.cpp +++ b/gfx/gl/EGLUtils.cpp @@ -23,7 +23,7 @@ CreateEGLImage(GLContext* gl, GLuint tex) MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl)); EGLClientBuffer clientBuffer = (EGLClientBuffer)((uint64_t)tex); - EGLContext eglContext = GLContextEGL::Cast(gl)->GetEGLContext(); + EGLContext eglContext = GLContextEGL::Cast(gl)->mContext; EGLImage image = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext, LOCAL_EGL_GL_TEXTURE_2D, @@ -42,7 +42,7 @@ EGLImageWrapper::Create(GLContext* gl, GLuint tex) GLLibraryEGL& library = sEGLLibrary; EGLDisplay display = EGL_DISPLAY(); - EGLContext eglContext = GLContextEGL::Cast(gl)->GetEGLContext(); + EGLContext eglContext = GLContextEGL::Cast(gl)->mContext; EGLClientBuffer clientBuffer = (EGLClientBuffer)((uint64_t)tex); EGLImage image = library.fCreateImage(display, eglContext, diff --git a/gfx/gl/GLBlitHelper.cpp b/gfx/gl/GLBlitHelper.cpp index 26bfb46287..82e595fc73 100644 --- a/gfx/gl/GLBlitHelper.cpp +++ b/gfx/gl/GLBlitHelper.cpp @@ -30,119 +30,6 @@ using mozilla::layers::PlanarYCbCrData; namespace mozilla { namespace gl { -static void -RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples, - GLenum aInternalFormat, const gfx::IntSize& aSize) -{ - if (aSamples) { - aGL->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, - aSamples, - aInternalFormat, - aSize.width, aSize.height); - } else { - aGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, - aInternalFormat, - aSize.width, aSize.height); - } -} - -GLuint -CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, - GLenum aType, const gfx::IntSize& aSize, bool linear) -{ - GLuint tex = 0; - aGL->fGenTextures(1, &tex); - ScopedBindTexture autoTex(aGL, tex); - - aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, - LOCAL_GL_TEXTURE_MIN_FILTER, linear ? LOCAL_GL_LINEAR - : LOCAL_GL_NEAREST); - aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, - LOCAL_GL_TEXTURE_MAG_FILTER, linear ? LOCAL_GL_LINEAR - : LOCAL_GL_NEAREST); - aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, - LOCAL_GL_CLAMP_TO_EDGE); - aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, - LOCAL_GL_CLAMP_TO_EDGE); - - aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, - 0, - aInternalFormat, - aSize.width, aSize.height, - 0, - aFormat, - aType, - nullptr); - - return tex; -} - -GLuint -CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, - const gfx::IntSize& aSize) -{ - MOZ_ASSERT(aFormats.color_texInternalFormat); - MOZ_ASSERT(aFormats.color_texFormat); - MOZ_ASSERT(aFormats.color_texType); - - return CreateTexture(aGL, - aFormats.color_texInternalFormat, - aFormats.color_texFormat, - aFormats.color_texType, - aSize); -} - - -GLuint -CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples, - const gfx::IntSize& aSize) -{ - GLuint rb = 0; - aGL->fGenRenderbuffers(1, &rb); - ScopedBindRenderbuffer autoRB(aGL, rb); - - RenderbufferStorageBySamples(aGL, aSamples, aFormat, aSize); - - return rb; -} - - -void -CreateRenderbuffersForOffscreen(GLContext* aGL, const GLFormats& aFormats, - const gfx::IntSize& aSize, bool aMultisample, - GLuint* aColorMSRB, GLuint* aDepthRB, - GLuint* aStencilRB) -{ - GLsizei samples = aMultisample ? aFormats.samples : 0; - if (aColorMSRB) { - MOZ_ASSERT(aFormats.samples > 0); - MOZ_ASSERT(aFormats.color_rbFormat); - - *aColorMSRB = CreateRenderbuffer(aGL, aFormats.color_rbFormat, samples, aSize); - } - - if (aDepthRB && - aStencilRB && - aFormats.depthStencil) - { - *aDepthRB = CreateRenderbuffer(aGL, aFormats.depthStencil, samples, aSize); - *aStencilRB = *aDepthRB; - } else { - if (aDepthRB) { - MOZ_ASSERT(aFormats.depth); - - *aDepthRB = CreateRenderbuffer(aGL, aFormats.depth, samples, aSize); - } - - if (aStencilRB) { - MOZ_ASSERT(aFormats.stencil); - - *aStencilRB = CreateRenderbuffer(aGL, aFormats.stencil, samples, aSize); - } - } -} - - GLBlitHelper::GLBlitHelper(GLContext* gl) : mGL(gl) , mTexBlit_Buffer(0) diff --git a/gfx/gl/GLBlitHelper.h b/gfx/gl/GLBlitHelper.h index b6bff759c0..224c87a145 100644 --- a/gfx/gl/GLBlitHelper.h +++ b/gfx/gl/GLBlitHelper.h @@ -27,48 +27,6 @@ namespace gl { class GLContext; -/** - * Helper function that creates a 2D texture aSize.width x aSize.height with - * storage type specified by aFormats. Returns GL texture object id. - * - * See mozilla::gl::CreateTexture. - */ -GLuint CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, - const gfx::IntSize& aSize); - -/** - * Helper function that creates a 2D texture aSize.width x aSize.height with - * storage type aInternalFormat. Returns GL texture object id. - * - * Initialize textyre parameters to: - * GL_TEXTURE_MIN_FILTER = GL_LINEAR - * GL_TEXTURE_MAG_FILTER = GL_LINEAR - * GL_TEXTURE_WRAP_S = GL_CLAMP_TO_EDGE - * GL_TEXTURE_WRAP_T = GL_CLAMP_TO_EDGE - */ -GLuint CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, - GLenum aType, const gfx::IntSize& aSize, bool linear = true); - -/** - * Helper function to create, potentially, multisample render buffers suitable - * for offscreen rendering. Buffers of size aSize.width x aSize.height with - * storage specified by aFormat. returns GL render buffer object id. - */ -GLuint CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples, - const gfx::IntSize& aSize); - -/** - * Helper function to create, potentially, multisample render buffers suitable - * for offscreen rendering. Buffers of size aSize.width x aSize.height with - * storage specified by aFormats. GL render buffer object ids are returned via - * aColorMSRB, aDepthRB, and aStencilRB - */ -void CreateRenderbuffersForOffscreen(GLContext* aGL, const GLFormats& aFormats, - const gfx::IntSize& aSize, bool aMultisample, - GLuint* aColorMSRB, GLuint* aDepthRB, - GLuint* aStencilRB); - - /** Buffer blitting helper */ class GLBlitHelper final { diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 29dd533dc8..fc7cf16620 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -304,7 +304,6 @@ GLContext::GLContext(const SurfaceCaps& caps, mRenderer(GLRenderer::Other), mHasRobustness(false), mTopError(LOCAL_GL_NO_ERROR), - mLocalErrorScope(nullptr), mSharedContext(sharedContext), mCaps(caps), mScreen(nullptr), @@ -2933,5 +2932,59 @@ GLContext::IsDrawingToDefaultFramebuffer() return Screen()->IsDrawFramebufferDefault(); } +GLuint +CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, + GLenum aType, const gfx::IntSize& aSize, bool linear) +{ + GLuint tex = 0; + aGL->fGenTextures(1, &tex); + ScopedBindTexture autoTex(aGL, tex); + + aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, + LOCAL_GL_TEXTURE_MIN_FILTER, linear ? LOCAL_GL_LINEAR + : LOCAL_GL_NEAREST); + aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, + LOCAL_GL_TEXTURE_MAG_FILTER, linear ? LOCAL_GL_LINEAR + : LOCAL_GL_NEAREST); + aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, + LOCAL_GL_CLAMP_TO_EDGE); + aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, + LOCAL_GL_CLAMP_TO_EDGE); + + aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, + 0, + aInternalFormat, + aSize.width, aSize.height, + 0, + aFormat, + aType, + nullptr); + + return tex; +} + +GLuint +CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, + const gfx::IntSize& aSize) +{ + MOZ_ASSERT(aFormats.color_texInternalFormat); + MOZ_ASSERT(aFormats.color_texFormat); + MOZ_ASSERT(aFormats.color_texType); + + GLenum internalFormat = aFormats.color_texInternalFormat; + GLenum unpackFormat = aFormats.color_texFormat; + GLenum unpackType = aFormats.color_texType; + if (aGL->IsANGLE()) { + MOZ_ASSERT(internalFormat == LOCAL_GL_RGBA); + MOZ_ASSERT(unpackFormat == LOCAL_GL_RGBA); + MOZ_ASSERT(unpackType == LOCAL_GL_UNSIGNED_BYTE); + internalFormat = LOCAL_GL_BGRA_EXT; + unpackFormat = LOCAL_GL_BGRA_EXT; + } + + return CreateTexture(aGL, internalFormat, unpackFormat, unpackType, aSize); +} + + } /* namespace gl */ } /* namespace mozilla */ diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index a8636b1c6c..58501d63c0 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -7,12 +7,13 @@ #ifndef GLCONTEXT_H_ #define GLCONTEXT_H_ -#include -#include -#include -#include #include +#include +#include +#include +#include #include +#include #ifdef DEBUG #include @@ -619,7 +620,7 @@ public: class LocalErrorScope; private: - LocalErrorScope* mLocalErrorScope; + std::stack mLocalErrorScopeStack; public: class LocalErrorScope { @@ -632,8 +633,7 @@ public: : mGL(gl) , mHasBeenChecked(false) { - MOZ_ASSERT(!mGL.mLocalErrorScope); - mGL.mLocalErrorScope = this; + mGL.mLocalErrorScopeStack.push(this); mGL.FlushErrors(); @@ -653,10 +653,10 @@ public: MOZ_ASSERT(mGL.fGetError() == LOCAL_GL_NO_ERROR); - mGL.mTopError = mOldTop; + MOZ_ASSERT(mGL.mLocalErrorScopeStack.top() == this); + mGL.mLocalErrorScopeStack.pop(); - MOZ_ASSERT(mGL.mLocalErrorScope == this); - mGL.mLocalErrorScope = nullptr; + mGL.mTopError = mOldTop; } }; @@ -738,7 +738,7 @@ private: } if (err != LOCAL_GL_NO_ERROR && - !mLocalErrorScope) + !mLocalErrorScopeStack.size()) { printf_stderr("[gl:%p] %s: Generated unexpected %s error." " (0x%04x)\n", this, funcName, @@ -3652,6 +3652,28 @@ MarkBitfieldByStrings(const std::vector& strList, } } +/** + * Helper function that creates a 2D texture aSize.width x aSize.height with + * storage type specified by aFormats. Returns GL texture object id. + * + * See mozilla::gl::CreateTexture. + */ +GLuint CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats, + const gfx::IntSize& aSize); + +/** + * Helper function that creates a 2D texture aSize.width x aSize.height with + * storage type aInternalFormat. Returns GL texture object id. + * + * Initialize textyre parameters to: + * GL_TEXTURE_MIN_FILTER = GL_LINEAR + * GL_TEXTURE_MAG_FILTER = GL_LINEAR + * GL_TEXTURE_WRAP_S = GL_CLAMP_TO_EDGE + * GL_TEXTURE_WRAP_T = GL_CLAMP_TO_EDGE + */ +GLuint CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat, + GLenum aType, const gfx::IntSize& aSize, bool linear = true); + } /* namespace gl */ } /* namespace mozilla */ diff --git a/gfx/gl/GLContextEGL.h b/gfx/gl/GLContextEGL.h index 5a4d3b7222..759431807a 100644 --- a/gfx/gl/GLContextEGL.h +++ b/gfx/gl/GLContextEGL.h @@ -92,16 +92,12 @@ public: // for the lifetime of this context. void HoldSurface(gfxASurface *aSurf); - EGLContext GetEGLContext() { - return mContext; - } - - EGLSurface GetEGLSurface() { + EGLSurface GetEGLSurface() const { return mSurface; } - EGLDisplay GetEGLDisplay() { - return EGL_DISPLAY(); + EGLDisplay GetEGLDisplay() const { + return sEGLLibrary.Display(); } bool BindTex2DOffscreen(GLContext *aOffscreen); @@ -112,15 +108,20 @@ public: CreateEGLPixmapOffscreenContext(const gfx::IntSize& size); static already_AddRefed - CreateEGLPBufferOffscreenContext(const gfx::IntSize& size); + CreateEGLPBufferOffscreenContext(const gfx::IntSize& size, + const SurfaceCaps& minCaps); protected: friend class GLContextProviderEGL; - EGLConfig mConfig; +public: + const EGLConfig mConfig; +protected: EGLSurface mSurface; +public: + const EGLContext mContext; +protected: EGLSurface mSurfaceOverride; - EGLContext mContext; nsRefPtr mThebesSurface; bool mBound; diff --git a/gfx/gl/GLContextProvider.h b/gfx/gl/GLContextProvider.h index 2a5d7c3284..8b4175a962 100644 --- a/gfx/gl/GLContextProvider.h +++ b/gfx/gl/GLContextProvider.h @@ -9,7 +9,6 @@ #include "GLContextTypes.h" #include "nsAutoPtr.h" #include "SurfaceTypes.h" -#include "mozilla/TypedEnumBits.h" #include "nsSize.h" // for gfx::IntSize (needed by GLContextProviderImpl.h below) @@ -18,16 +17,6 @@ class nsIWidget; namespace mozilla { namespace gl { -enum class CreateContextFlags : int8_t { - NONE = 0, - REQUIRE_COMPAT_PROFILE = 1 << 0, - // Force the use of hardware backed GL, don't allow software implementations. - FORCE_ENABLE_HARDWARE = 1 << 1, - /* Don't force discrete GPU to be used (if applicable) */ - ALLOW_OFFLINE_RENDERER = 1 << 2, -}; -MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags) - #define IN_GL_CONTEXT_PROVIDER_H // Null is always there @@ -36,47 +25,45 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags) #undef GL_CONTEXT_PROVIDER_NAME #ifdef XP_WIN -#define GL_CONTEXT_PROVIDER_NAME GLContextProviderWGL -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME -#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderWGL -#define DEFAULT_IMPL WGL + #define GL_CONTEXT_PROVIDER_NAME GLContextProviderWGL + #include "GLContextProviderImpl.h" + #undef GL_CONTEXT_PROVIDER_NAME + #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderWGL + #define DEFAULT_IMPL WGL #endif #ifdef XP_MACOSX -#define GL_CONTEXT_PROVIDER_NAME GLContextProviderCGL -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME -#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderCGL + #define GL_CONTEXT_PROVIDER_NAME GLContextProviderCGL + #include "GLContextProviderImpl.h" + #undef GL_CONTEXT_PROVIDER_NAME + #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderCGL +#endif + +#if defined(MOZ_X11) + #define GL_CONTEXT_PROVIDER_NAME GLContextProviderGLX + #include "GLContextProviderImpl.h" + #undef GL_CONTEXT_PROVIDER_NAME + #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderGLX #endif -#if defined(ANDROID) || defined(XP_WIN) #define GL_CONTEXT_PROVIDER_NAME GLContextProviderEGL #include "GLContextProviderImpl.h" #undef GL_CONTEXT_PROVIDER_NAME #ifndef GL_CONTEXT_PROVIDER_DEFAULT -#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEGL -#endif + #define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEGL #endif #ifdef MOZ_GL_PROVIDER -#define GL_CONTEXT_PROVIDER_NAME MOZ_GL_PROVIDER -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME -#define GL_CONTEXT_PROVIDER_DEFAULT MOZ_GL_PROVIDER -#endif - -#if defined(MOZ_X11) && !defined(GL_CONTEXT_PROVIDER_DEFAULT) -#define GL_CONTEXT_PROVIDER_NAME GLContextProviderGLX -#include "GLContextProviderImpl.h" -#undef GL_CONTEXT_PROVIDER_NAME -#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderGLX + #define GL_CONTEXT_PROVIDER_NAME MOZ_GL_PROVIDER + #include "GLContextProviderImpl.h" + #undef GL_CONTEXT_PROVIDER_NAME + #define GL_CONTEXT_PROVIDER_DEFAULT MOZ_GL_PROVIDER #endif #ifdef GL_CONTEXT_PROVIDER_DEFAULT -typedef GL_CONTEXT_PROVIDER_DEFAULT GLContextProvider; + typedef GL_CONTEXT_PROVIDER_DEFAULT GLContextProvider; #else -typedef GLContextProviderNull GLContextProvider; + typedef GLContextProviderNull GLContextProvider; #endif #undef IN_GL_CONTEXT_PROVIDER_H diff --git a/gfx/gl/GLContextProviderCGL.mm b/gfx/gl/GLContextProviderCGL.mm index dcf7e5234f..049829ad5d 100644 --- a/gfx/gl/GLContextProviderCGL.mm +++ b/gfx/gl/GLContextProviderCGL.mm @@ -319,16 +319,17 @@ GLContextProviderCGL::CreateHeadless(CreateContextFlags flags) already_AddRefed GLContextProviderCGL::CreateOffscreen(const IntSize& size, - const SurfaceCaps& caps, + const SurfaceCaps& minCaps, CreateContextFlags flags) { - nsRefPtr glContext = CreateHeadless(flags); - if (!glContext->InitOffscreen(size, caps)) { - NS_WARNING("Failed during InitOffscreen."); + RefPtr gl = CreateHeadless(flags); + if (!gl) return nullptr; - } - return glContext.forget(); + if (!gl->InitOffscreen(size, minCaps)) + return nullptr; + + return gl.forget(); } static nsRefPtr gGlobalContext; diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index c819d8dc6b..5983ed128c 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -3,116 +3,108 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "mozilla/ArrayUtils.h" - -#include "GLContextEGL.h" +#if defined(MOZ_WIDGET_GTK) + #include + // we're using default display for now + #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow*)aWidget->GetNativeData(NS_NATIVE_WINDOW))) +#elif defined(MOZ_WIDGET_QT) + #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW)) +#else + #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW)) +#endif #if defined(XP_UNIX) + #ifdef MOZ_WIDGET_GONK + #include "libdisplay/GonkDisplay.h" + #include "nsWindow.h" + #include "nsScreenManagerGonk.h" + #endif -#ifdef MOZ_WIDGET_GTK -#include -// we're using default display for now -#define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW)) -#elif defined(MOZ_WIDGET_QT) -#define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)(aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW)) -#elif defined(MOZ_WIDGET_GONK) -#define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW)) -#include "libdisplay/GonkDisplay.h" -#include "nsWindow.h" -#include "nsScreenManagerGonk.h" -#endif + #ifdef ANDROID + /* from widget */ + #ifdef MOZ_WIDGET_ANDROID + #include "AndroidBridge.h" + #endif -#if defined(ANDROID) -/* from widget */ -#if defined(MOZ_WIDGET_ANDROID) -#include "AndroidBridge.h" -#endif + #include + #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) -#include -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) + #ifdef MOZ_WIDGET_GONK + #include "cutils/properties.h" + #include -# if defined(MOZ_WIDGET_GONK) -# include "cutils/properties.h" -# include + using namespace android; + #endif + #endif -using namespace android; -# endif - -#endif - -#define GLES2_LIB "libGLESv2.so" -#define GLES2_LIB2 "libGLESv2.so.2" + #define GLES2_LIB "libGLESv2.so" + #define GLES2_LIB2 "libGLESv2.so.2" #elif defined(XP_WIN) + #include "nsIFile.h" -#include "nsIFile.h" + #define GLES2_LIB "libGLESv2.dll" -#define GLES2_LIB "libGLESv2.dll" + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN 1 + #endif -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif + #include -#include - -// a little helper -class AutoDestroyHWND { -public: - AutoDestroyHWND(HWND aWnd = nullptr) - : mWnd(aWnd) - { - } - - ~AutoDestroyHWND() { - if (mWnd) { - ::DestroyWindow(mWnd); + // a little helper + class AutoDestroyHWND { + public: + AutoDestroyHWND(HWND aWnd = nullptr) + : mWnd(aWnd) + { } - } - operator HWND() { - return mWnd; - } - - HWND forget() { - HWND w = mWnd; - mWnd = nullptr; - return w; - } - - HWND operator=(HWND aWnd) { - if (mWnd && mWnd != aWnd) { - ::DestroyWindow(mWnd); + ~AutoDestroyHWND() { + if (mWnd) { + ::DestroyWindow(mWnd); + } } - mWnd = aWnd; - return mWnd; - } - HWND mWnd; -}; + operator HWND() { + return mWnd; + } + HWND forget() { + HWND w = mWnd; + mWnd = nullptr; + return w; + } + + HWND operator=(HWND aWnd) { + if (mWnd && mWnd != aWnd) { + ::DestroyWindow(mWnd); + } + mWnd = aWnd; + return mWnd; + } + + HWND mWnd; + }; #else - -#error "Platform not recognized" - + #error "Platform not recognized" #endif -#include "mozilla/Preferences.h" -#include "gfxUtils.h" -#include "gfxFailure.h" #include "gfxASurface.h" +#include "gfxCrashReporterUtils.h" +#include "gfxFailure.h" #include "gfxPlatform.h" +#include "gfxUtils.h" +#include "GLBlitHelper.h" +#include "GLContextEGL.h" #include "GLContextProvider.h" #include "GLLibraryEGL.h" -#include "TextureImageEGL.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/Preferences.h" #include "nsDebug.h" -#include "nsThreadUtils.h" - #include "nsIWidget.h" - -#include "gfxCrashReporterUtils.h" - +#include "nsThreadUtils.h" #include "ScopedGLHelpers.h" -#include "GLBlitHelper.h" +#include "TextureImageEGL.h" using namespace mozilla::gfx; @@ -190,17 +182,15 @@ DestroySurface(EGLSurface oldSurface) { static EGLSurface CreateSurfaceForWindow(nsIWidget* widget, const EGLConfig& config) { - EGLSurface newSurface = EGL_NO_SURFACE; + EGLSurface newSurface = nullptr; #ifdef MOZ_WIDGET_ANDROID mozilla::AndroidBridge::Bridge()->RegisterCompositor(); newSurface = mozilla::AndroidBridge::Bridge()->CreateEGLSurfaceForCompositor(); - if (newSurface == EGL_NO_SURFACE) { - return EGL_NO_SURFACE; - } -#elif defined(XP_WIN) +#else MOZ_ASSERT(widget != nullptr); - newSurface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, GET_NATIVE_WINDOW(widget), 0); + newSurface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, + GET_NATIVE_WINDOW(widget), 0); #endif return newSurface; } @@ -215,8 +205,8 @@ GLContextEGL::GLContextEGL( : GLContext(caps, shareContext, isOffscreen) , mConfig(config) , mSurface(surface) - , mSurfaceOverride(EGL_NO_SURFACE) , mContext(context) + , mSurfaceOverride(EGL_NO_SURFACE) , mThebesSurface(nullptr) , mBound(false) , mIsPBuffer(false) @@ -351,7 +341,8 @@ GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) { } mSurfaceOverride = surf; - MakeCurrent(true); + DebugOnly ok = MakeCurrent(true); + MOZ_ASSERT(ok); } bool @@ -425,7 +416,7 @@ GLContextEGL::RenewSurface() { // If we get here, then by definition we know that we want to get a new surface. ReleaseSurface(); mSurface = mozilla::gl::CreateSurfaceForWindow(nullptr, mConfig); // the nullptr here is where we assume Android. - if (mSurface == EGL_NO_SURFACE) { + if (!mSurface) { return false; } return MakeCurrent(true); @@ -490,6 +481,10 @@ GLContextEGL::CreateSurfaceForWindow(nsIWidget* aWidget) } EGLSurface surface = mozilla::gl::CreateSurfaceForWindow(aWidget, config); + if (!surface) { + MOZ_CRASH("Failed to create EGLSurface for window!\n"); + return nullptr; + } return surface; } @@ -780,8 +775,7 @@ GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget) } EGLSurface surface = mozilla::gl::CreateSurfaceForWindow(aWidget, config); - - if (surface == EGL_NO_SURFACE) { + if (!surface) { MOZ_CRASH("Failed to create EGLSurface!\n"); return nullptr; } @@ -839,60 +833,144 @@ GLContextProviderEGL::DestroyEGLSurface(EGLSurface surface) } #endif // defined(ANDROID) -already_AddRefed -GLContextEGL::CreateEGLPBufferOffscreenContext(const mozilla::gfx::IntSize& size) +static void +FillContextAttribs(bool alpha, bool depth, bool stencil, bool bpp16, + nsTArray* out) { - EGLConfig config; - EGLSurface surface; + out->AppendElement(LOCAL_EGL_SURFACE_TYPE); + out->AppendElement(LOCAL_EGL_PBUFFER_BIT); - const EGLint numConfigs = 1; // We only need one. - EGLConfig configs[numConfigs]; + out->AppendElement(LOCAL_EGL_RENDERABLE_TYPE); + out->AppendElement(LOCAL_EGL_OPENGL_ES2_BIT); + + out->AppendElement(LOCAL_EGL_RED_SIZE); + if (bpp16) { + out->AppendElement(alpha ? 4 : 5); + } else { + out->AppendElement(8); + } + + out->AppendElement(LOCAL_EGL_GREEN_SIZE); + if (bpp16) { + out->AppendElement(alpha ? 4 : 6); + } else { + out->AppendElement(8); + } + + out->AppendElement(LOCAL_EGL_BLUE_SIZE); + if (bpp16) { + out->AppendElement(alpha ? 4 : 5); + } else { + out->AppendElement(8); + } + + out->AppendElement(LOCAL_EGL_ALPHA_SIZE); + if (alpha) { + out->AppendElement(bpp16 ? 4 : 8); + } else { + out->AppendElement(0); + } + + out->AppendElement(LOCAL_EGL_DEPTH_SIZE); + out->AppendElement(depth ? 16 : 0); + + out->AppendElement(LOCAL_EGL_STENCIL_SIZE); + out->AppendElement(stencil ? 8 : 0); + + // EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS + out->AppendElement(LOCAL_EGL_NONE); + out->AppendElement(0); + + out->AppendElement(0); + out->AppendElement(0); +} + +static GLint +GetAttrib(GLLibraryEGL* egl, EGLConfig config, EGLint attrib) +{ + EGLint bits = 0; + egl->fGetConfigAttrib(egl->Display(), config, attrib, &bits); + MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS); + + return bits; +} + +static EGLConfig +ChooseConfig(GLLibraryEGL* egl, const SurfaceCaps& minCaps, + SurfaceCaps* const out_configCaps) +{ + nsTArray configAttribList; + FillContextAttribs(minCaps.alpha, minCaps.depth, minCaps.stencil, minCaps.bpp16, + &configAttribList); + + const EGLint* configAttribs = configAttribList.Elements(); + + // We're guaranteed to get at least minCaps, and the sorting dictated by the spec for + // eglChooseConfig reasonably assures that a reasonable 'best' config is on top. + const EGLint kMaxConfigs = 1; + EGLConfig configs[kMaxConfigs]; EGLint foundConfigs = 0; - if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), - kEGLConfigAttribsOffscreenPBuffer, - configs, numConfigs, - &foundConfigs) + if (!egl->fChooseConfig(egl->Display(), configAttribs, configs, kMaxConfigs, + &foundConfigs) || foundConfigs == 0) { - NS_WARNING("No EGL Config for minimal PBuffer!"); + return EGL_NO_CONFIG; + } + + EGLConfig config = configs[0]; + + *out_configCaps = minCaps; // Pick up any preserve, etc. + out_configCaps->color = true; + out_configCaps->alpha = bool(GetAttrib(egl, config, LOCAL_EGL_ALPHA_SIZE)); + out_configCaps->depth = bool(GetAttrib(egl, config, LOCAL_EGL_DEPTH_SIZE)); + out_configCaps->stencil = bool(GetAttrib(egl, config, LOCAL_EGL_STENCIL_SIZE)); + out_configCaps->bpp16 = (GetAttrib(egl, config, LOCAL_EGL_RED_SIZE) < 8); + + return config; +} + +/*static*/ already_AddRefed +GLContextEGL::CreateEGLPBufferOffscreenContext(const mozilla::gfx::IntSize& size, + const SurfaceCaps& minCaps) +{ + SurfaceCaps configCaps; + EGLConfig config = ChooseConfig(&sEGLLibrary, minCaps, &configCaps); + if (config == EGL_NO_CONFIG) { + NS_WARNING("Failed to find a compatible config."); return nullptr; } - // We absolutely don't care, so just pick the first one. - config = configs[0]; if (GLContext::ShouldSpew()) sEGLLibrary.DumpEGLConfig(config); mozilla::gfx::IntSize pbSize(size); - surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config, - LOCAL_EGL_NONE, - pbSize); + EGLSurface surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config, + LOCAL_EGL_NONE, + pbSize); if (!surface) { NS_WARNING("Failed to create PBuffer for context!"); return nullptr; } - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - nsRefPtr glContext = - GLContextEGL::CreateGLContext(dummyCaps, - nullptr, true, - config, surface); - if (!glContext) { + + RefPtr gl = GLContextEGL::CreateGLContext(configCaps, nullptr, true, + config, surface); + if (!gl) { NS_WARNING("Failed to create GLContext from PBuffer"); - sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); + sEGLLibrary.fDestroySurface(sEGLLibrary.Display(), surface); return nullptr; } - if (!glContext->Init()) { + if (!gl->Init()) { NS_WARNING("Failed to initialize GLContext!"); // GLContextEGL::dtor will destroy |surface| for us. return nullptr; } - return glContext.forget(); + return gl.forget(); } -already_AddRefed +/*static*/ already_AddRefed GLContextEGL::CreateEGLPixmapOffscreenContext(const mozilla::gfx::IntSize& size) { gfxASurface *thebesSurface = nullptr; @@ -932,49 +1010,82 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const mozilla::gfx::IntSize& size) return glContext.forget(); } -already_AddRefed +/*static*/ already_AddRefed GLContextProviderEGL::CreateHeadless(CreateContextFlags flags) { - if (!sEGLLibrary.EnsureInitialized(bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE))) { + bool forceEnableHardware = bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE); + if (!sEGLLibrary.EnsureInitialized(forceEnableHardware)) return nullptr; - } mozilla::gfx::IntSize dummySize = mozilla::gfx::IntSize(16, 16); - nsRefPtr glContext; - glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize); - if (!glContext) - return nullptr; - - return glContext.forget(); + SurfaceCaps dummyCaps = SurfaceCaps::Any(); + return GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize, dummyCaps); } // Under EGL, on Android, pbuffers are supported fine, though // often without the ability to texture from them directly. -already_AddRefed +/*static*/ already_AddRefed GLContextProviderEGL::CreateOffscreen(const mozilla::gfx::IntSize& size, - const SurfaceCaps& caps, + const SurfaceCaps& minCaps, CreateContextFlags flags) { - nsRefPtr glContext = CreateHeadless(flags); - if (!glContext) + bool forceEnableHardware = bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE); + if (!sEGLLibrary.EnsureInitialized(forceEnableHardware)) return nullptr; - if (!glContext->InitOffscreen(size, caps)) + bool canOffscreenUseHeadless = true; + if (sEGLLibrary.IsANGLE()) { + // ANGLE needs to use PBuffers. + canOffscreenUseHeadless = false; + } + + RefPtr gl; + SurfaceCaps minOffscreenCaps = minCaps; + + if (canOffscreenUseHeadless) { + gl = CreateHeadless(flags); + if (!gl) + return nullptr; + } else { + SurfaceCaps minBackbufferCaps = minOffscreenCaps; + if (minOffscreenCaps.antialias) { + minBackbufferCaps.antialias = false; + minBackbufferCaps.depth = false; + minBackbufferCaps.stencil = false; + } + + gl = GLContextEGL::CreateEGLPBufferOffscreenContext(size, minBackbufferCaps); + if (!gl) + return nullptr; + + // Pull the actual resulting caps to ensure that our offscreen matches our + // backbuffer. + minOffscreenCaps.alpha = gl->Caps().alpha; + if (!minOffscreenCaps.antialias) { + // Only update these if we don't have AA. If we do have AA, we ignore + // backbuffer depth/stencil. + minOffscreenCaps.depth = gl->Caps().depth; + minOffscreenCaps.stencil = gl->Caps().stencil; + } + } + + // Init the offscreen with the updated offscreen caps. + if (!gl->InitOffscreen(size, minOffscreenCaps)) return nullptr; - return glContext.forget(); + return gl.forget(); } // Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225) // and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257) // and 3) each EGL context eats 750k on B2G (bug 813783) -GLContext* +/*static*/ GLContext* GLContextProviderEGL::GetGlobalContext() { return nullptr; } -void +/*static*/ void GLContextProviderEGL::Shutdown() { } diff --git a/gfx/gl/GLContextProviderGLX.cpp b/gfx/gl/GLContextProviderGLX.cpp index 81c7c7e645..1fd047e228 100644 --- a/gfx/gl/GLContextProviderGLX.cpp +++ b/gfx/gl/GLContextProviderGLX.cpp @@ -76,6 +76,7 @@ GLXLibrary::EnsureInitialized() if (!mOGLLibrary) { const char* libGLfilename = nullptr; + bool forceFeatureReport = false; // see e.g. bug 608526: it is intrinsically interesting to know whether we have dynamically linked to libGL.so.1 // because at least the NVIDIA implementation requires an executable stack, which causes mprotect calls, @@ -86,11 +87,13 @@ GLXLibrary::EnsureInitialized() libGLfilename = "libGL.so.1"; #endif + ScopedGfxFeatureReporter reporter(libGLfilename, forceFeatureReport); mOGLLibrary = PR_LoadLibrary(libGLfilename); if (!mOGLLibrary) { NS_WARNING("Couldn't load OpenGL shared library."); return false; } + reporter.SetSuccessful(); } if (PR_GetEnv("MOZ_GLX_DEBUG")) { @@ -232,7 +235,9 @@ GLXLibrary::EnsureInitialized() } if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness") && - GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) { + GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_robustness, + (GLLibraryLoader::PlatformLookupFunction)&xGetProcAddress)) + { mHasRobustness = true; } @@ -1123,75 +1128,96 @@ GLContextProviderGLX::CreateForWindow(nsIWidget *aWidget) return glContext.forget(); } -static already_AddRefed -CreateOffscreenPixmapContext(const IntSize& size) +static bool +ChooseConfig(GLXLibrary* glx, Display* display, int screen, const SurfaceCaps& minCaps, + ScopedXFree* const out_scopedConfigArr, + GLXFBConfig* const out_config, int* const out_visid) { - GLXLibrary& glx = sGLXLibrary; - if (!glx.EnsureInitialized()) { - return nullptr; - } + ScopedXFree& scopedConfigArr = *out_scopedConfigArr; - Display *display = DefaultXDisplay(); - int xscreen = DefaultScreen(display); + if (minCaps.antialias) + return false; int attribs[] = { LOCAL_GLX_DRAWABLE_TYPE, LOCAL_GLX_PIXMAP_BIT, LOCAL_GLX_X_RENDERABLE, True, + LOCAL_GLX_RED_SIZE, 8, + LOCAL_GLX_GREEN_SIZE, 8, + LOCAL_GLX_BLUE_SIZE, 8, + LOCAL_GLX_ALPHA_SIZE, minCaps.alpha ? 8 : 0, + LOCAL_GLX_DEPTH_SIZE, minCaps.depth ? 16 : 0, + LOCAL_GLX_STENCIL_SIZE, minCaps.stencil ? 8 : 0, 0 }; + int numConfigs = 0; + scopedConfigArr = glx->xChooseFBConfig(display, screen, attribs, &numConfigs); + if (!scopedConfigArr || !numConfigs) + return false; - ScopedXFree cfgs; - cfgs = glx.xChooseFBConfig(display, - xscreen, - attribs, - &numConfigs); - if (!cfgs) { - return nullptr; - } + // Issues with glxChooseFBConfig selection and sorting: + // * ALPHA_SIZE is sorted as 'largest total RGBA bits first'. If we don't request + // alpha bits, we'll probably get RGBA anyways, since 32 is more than 24. + // * DEPTH_SIZE is sorted largest first, including for `0` inputs. + // * STENCIL_SIZE is smallest first, but it might return `8` even though we ask for + // `0`. - MOZ_ASSERT(numConfigs > 0, - "glXChooseFBConfig() failed to match our requested format and " - "violated its spec!"); - - int visid = None; - int chosenIndex = 0; + // For now, we don't care about these. We *will* care when we do XPixmap sharing. for (int i = 0; i < numConfigs; ++i) { - int dtype; + GLXFBConfig curConfig = scopedConfigArr[i]; - if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_DRAWABLE_TYPE, &dtype) != Success - || !(dtype & LOCAL_GLX_PIXMAP_BIT)) - { - continue; - } - if (glx.xGetFBConfigAttrib(display, cfgs[i], LOCAL_GLX_VISUAL_ID, &visid) != Success - || visid == 0) + int visid; + if (glx->xGetFBConfigAttrib(display, curConfig, LOCAL_GLX_VISUAL_ID, &visid) + != Success) { continue; } - chosenIndex = i; - break; + if (!visid) + continue; + + *out_config = curConfig; + *out_visid = visid; + return true; } - if (!visid) { - NS_WARNING("glXChooseFBConfig() didn't give us any configs with visuals!"); + return false; +} + +static already_AddRefed +CreateOffscreenPixmapContext(const IntSize& size, const SurfaceCaps& minCaps) +{ + GLXLibrary* glx = &sGLXLibrary; + if (!glx->EnsureInitialized()) + return nullptr; + + Display* display = DefaultXDisplay(); + int screen = DefaultScreen(display); + + ScopedXFree scopedConfigArr; + GLXFBConfig config; + int visid; + if (!ChooseConfig(glx, display, screen, minCaps, &scopedConfigArr, &config, &visid)) { + NS_WARNING("Failed to find a compatible config."); return nullptr; } - Visual *visual; + Visual* visual; int depth; FindVisualAndDepth(display, visid, &visual, &depth); - ScopedXErrorHandler xErrorHandler; - GLXPixmap glxpixmap = 0; - bool error = false; - IntSize dummySize(16, 16); - nsRefPtr xsurface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display), - visual, - dummySize); - if (xsurface->CairoStatus() != 0) { + ScopedXErrorHandler xErrorHandler; + bool error = false; + // Must be declared before goto: + Drawable drawable; + GLXPixmap pixmap; + + gfx::IntSize dummySize(16, 16); + RefPtr surface = gfxXlibSurface::Create(DefaultScreenOfDisplay(display), + visual, + dummySize); + if (surface->CairoStatus() != 0) { error = true; goto DONE_CREATING_PIXMAP; } @@ -1199,73 +1225,60 @@ CreateOffscreenPixmapContext(const IntSize& size) // Handle slightly different signature between glXCreatePixmap and // its pre-GLX-1.3 extension equivalent (though given the ABI, we // might not need to). - if (glx.GLXVersionCheck(1, 3)) { - glxpixmap = glx.xCreatePixmap(display, - cfgs[chosenIndex], - xsurface->XDrawable(), - nullptr); + drawable = surface->XDrawable(); + if (glx->GLXVersionCheck(1, 3)) { + pixmap = glx->xCreatePixmap(display, config, drawable, nullptr); } else { - glxpixmap = glx.xCreateGLXPixmapWithConfig(display, - cfgs[chosenIndex], - xsurface-> - XDrawable()); + pixmap = glx->xCreateGLXPixmapWithConfig(display, config, drawable); } - if (glxpixmap == 0) { + + if (pixmap == 0) { error = true; } DONE_CREATING_PIXMAP: - nsRefPtr glContext; bool serverError = xErrorHandler.SyncAndGetError(display); + if (error || serverError) + return nullptr; - if (!error && // earlier recorded error - !serverError) - { - // We might have an alpha channel, but it doesn't matter. - SurfaceCaps dummyCaps = SurfaceCaps::Any(); - GLContextGLX* shareContext = GetGlobalContextGLX(); - - glContext = GLContextGLX::CreateGLContext(dummyCaps, - shareContext, - true, - display, - glxpixmap, - cfgs[chosenIndex], - true, - xsurface); - } - - return glContext.forget(); + GLContextGLX* shareContext = GetGlobalContextGLX(); + return GLContextGLX::CreateGLContext(minCaps, shareContext, true, display, pixmap, + config, true, surface); } -already_AddRefed +/*static*/ already_AddRefed GLContextProviderGLX::CreateHeadless(CreateContextFlags) { IntSize dummySize = IntSize(16, 16); - nsRefPtr glContext = CreateOffscreenPixmapContext(dummySize); - if (!glContext) - return nullptr; - - return glContext.forget(); + SurfaceCaps dummyCaps = SurfaceCaps::Any(); + return CreateOffscreenPixmapContext(dummySize, dummyCaps); } -already_AddRefed +/*static*/ already_AddRefed GLContextProviderGLX::CreateOffscreen(const IntSize& size, - const SurfaceCaps& caps, + const SurfaceCaps& minCaps, CreateContextFlags flags) { - nsRefPtr glContext = CreateHeadless(flags); - if (!glContext) + SurfaceCaps minBackbufferCaps = minCaps; + if (minCaps.antialias) { + minBackbufferCaps.antialias = false; + minBackbufferCaps.depth = false; + minBackbufferCaps.stencil = false; + } + + RefPtr gl; + gl = CreateOffscreenPixmapContext(size, minBackbufferCaps); + if (!gl) return nullptr; - if (!glContext->InitOffscreen(size, caps)) + if (!gl->InitOffscreen(size, minCaps)) return nullptr; - return glContext.forget(); + return gl.forget(); } -GLContext* +/*static*/ GLContext* GLContextProviderGLX::GetGlobalContext() { static bool checkedContextSharing = false; @@ -1286,17 +1299,19 @@ GLContextProviderGLX::GetGlobalContext() triedToCreateContext = true; IntSize dummySize = IntSize(16, 16); + SurfaceCaps dummyCaps = SurfaceCaps::Any(); // StaticPtr doesn't support assignments from already_AddRefed, // so use a temporary nsRefPtr to make the reference counting // fall out correctly. - nsRefPtr holder = CreateOffscreenPixmapContext(dummySize); + RefPtr holder; + holder = CreateOffscreenPixmapContext(dummySize, dummyCaps); gGlobalContext = holder; } return gGlobalContext; } -void +/*static*/ void GLContextProviderGLX::Shutdown() { gGlobalContext = nullptr; diff --git a/gfx/gl/GLContextProviderImpl.h b/gfx/gl/GLContextProviderImpl.h index a65f7cbbed..c3bcb5c05d 100644 --- a/gfx/gl/GLContextProviderImpl.h +++ b/gfx/gl/GLContextProviderImpl.h @@ -54,16 +54,18 @@ public: * resource sharing can be avoided on the target platform, it will * be, in order to isolate the offscreen context. * - * @param size The initial size of this offscreen context. - * @param caps The SurfaceCaps for this offscreen context. - * @param flags The set of CreateContextFlags to be used for this - * offscreen context. + * @param size The initial size of this offscreen context. + * @param minCaps The required SurfaceCaps for this offscreen context. The resulting + * context *may* have more/better caps than requested, but it cannot + * have fewer/worse caps than requested. + * @param flags The set of CreateContextFlags to be used for this + * offscreen context. * * @return Context to use for offscreen rendering */ static already_AddRefed CreateOffscreen(const mozilla::gfx::IntSize& size, - const SurfaceCaps& caps, + const SurfaceCaps& minCaps, CreateContextFlags flags); // Just create a context. We'll add offscreen stuff ourselves. diff --git a/gfx/gl/GLContextProviderWGL.cpp b/gfx/gl/GLContextProviderWGL.cpp index 7e241c106c..564804146f 100644 --- a/gfx/gl/GLContextProviderWGL.cpp +++ b/gfx/gl/GLContextProviderWGL.cpp @@ -601,7 +601,7 @@ CreateWindowOffscreenContext() return glContext.forget(); } -already_AddRefed +/*static*/ already_AddRefed GLContextProviderWGL::CreateHeadless(CreateContextFlags) { if (!sWGLLib.EnsureInitialized()) { @@ -634,24 +634,24 @@ GLContextProviderWGL::CreateHeadless(CreateContextFlags) return retGL.forget(); } -already_AddRefed +/*static*/ already_AddRefed GLContextProviderWGL::CreateOffscreen(const IntSize& size, - const SurfaceCaps& caps, + const SurfaceCaps& minCaps, CreateContextFlags flags) { - nsRefPtr glContext = CreateHeadless(flags); - if (!glContext) + RefPtr gl = CreateHeadless(flags); + if (!gl) return nullptr; - if (!glContext->InitOffscreen(size, caps)) + if (!gl->InitOffscreen(size, minCaps)) return nullptr; - return glContext.forget(); + return gl.forget(); } static nsRefPtr gGlobalContext; -GLContext * +/*static*/ GLContext* GLContextProviderWGL::GetGlobalContext() { if (!sWGLLib.EnsureInitialized()) { @@ -679,7 +679,7 @@ GLContextProviderWGL::GetGlobalContext() return static_cast(gGlobalContext); } -void +/*static*/ void GLContextProviderWGL::Shutdown() { gGlobalContext = nullptr; diff --git a/gfx/gl/GLContextTypes.h b/gfx/gl/GLContextTypes.h index 979790bb1e..a9225e2d83 100644 --- a/gfx/gl/GLContextTypes.h +++ b/gfx/gl/GLContextTypes.h @@ -7,6 +7,7 @@ #define GLCONTEXT_TYPES_H_ #include "GLTypes.h" +#include "mozilla/TypedEnumBits.h" namespace mozilla { namespace gl { @@ -43,6 +44,16 @@ struct GLFormats GLsizei samples; }; +enum class CreateContextFlags : int8_t { + NONE = 0, + REQUIRE_COMPAT_PROFILE = 1 << 0, + // Force the use of hardware backed GL, don't allow software implementations. + FORCE_ENABLE_HARDWARE = 1 << 1, + /* Don't force discrete GPU to be used (if applicable) */ + ALLOW_OFFLINE_RENDERER = 1 << 2, +}; +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags) + } /* namespace gl */ } /* namespace mozilla */ diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp index 63c270df63..9f830e5495 100644 --- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -37,8 +37,8 @@ static const char *sEGLExtensionNames[] = { "EGL_KHR_fence_sync", "EGL_ANDROID_native_fence_sync", "EGL_ANDROID_image_crop", - "ANGLE_platform_angle", - "ANGLE_platform_angle_d3d" + "EGL_ANGLE_platform_angle", + "EGL_ANGLE_platform_angle_d3d" }; #if defined(ANDROID) diff --git a/gfx/gl/GLLibraryEGL.h b/gfx/gl/GLLibraryEGL.h index 225dc8fd10..c4cd44b811 100644 --- a/gfx/gl/GLLibraryEGL.h +++ b/gfx/gl/GLLibraryEGL.h @@ -17,40 +17,32 @@ #include #include -#if defined(XP_WIN) +#ifdef XP_WIN + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN 1 + #endif -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif - -#include - -typedef HDC EGLNativeDisplayType; -typedef HBITMAP EGLNativePixmapType; -typedef HWND EGLNativeWindowType; - -#define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW)) + #include + typedef HDC EGLNativeDisplayType; + typedef HBITMAP EGLNativePixmapType; + typedef HWND EGLNativeWindowType; #else -typedef void *EGLNativeDisplayType; -typedef void *EGLNativePixmapType; -typedef void *EGLNativeWindowType; + typedef void* EGLNativeDisplayType; + typedef void* EGLNativePixmapType; + typedef void* EGLNativeWindowType; -#ifdef ANDROID -// We only need to explicitly dlopen egltrace -// on android as we can use LD_PRELOAD or other tricks -// on other platforms. We look for it in /data/local -// as that's writeable by all users -// -// This should really go in GLLibraryEGL.cpp but we currently reference -// APITRACE_LIB in GLContextProviderEGL.cpp. Further refactoring -// will come in subsequent patches on Bug 732865 -#define APITRACE_LIB "/data/local/tmp/egltrace.so" - -#ifdef MOZ_WIDGET_ANDROID - -#endif // MOZ_WIDGET_ANDROID -#endif // ANDROID + #ifdef ANDROID + // We only need to explicitly dlopen egltrace + // on android as we can use LD_PRELOAD or other tricks + // on other platforms. We look for it in /data/local + // as that's writeable by all users + // + // This should really go in GLLibraryEGL.cpp but we currently reference + // APITRACE_LIB in GLContextProviderEGL.cpp. Further refactoring + // will come in subsequent patches on Bug 732865 + #define APITRACE_LIB "/data/local/tmp/egltrace.so" + #endif #endif #if defined(MOZ_X11) diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp index 24dd286752..f81926981c 100755 --- a/gfx/gl/GLScreenBuffer.cpp +++ b/gfx/gl/GLScreenBuffer.cpp @@ -486,9 +486,16 @@ GLScreenBuffer::Swap(const gfx::IntSize& size) //uint32_t srcPixel = ReadPixel(src); //uint32_t destPixel = ReadPixel(dest); //printf_stderr("Before: src: 0x%08x, dest: 0x%08x\n", srcPixel, destPixel); +#ifdef DEBUG + GLContext::LocalErrorScope errorScope(*mGL); +#endif SharedSurface::ProdCopy(src, dest, mFactory.get()); +#ifdef DEBUG + MOZ_ASSERT(!errorScope.GetError()); +#endif + //srcPixel = ReadPixel(src); //destPixel = ReadPixel(dest); //printf_stderr("After: src: 0x%08x, dest: 0x%08x\n", srcPixel, destPixel); @@ -611,6 +618,79 @@ GLScreenBuffer::IsReadFramebufferDefault() const return SharedSurf()->mAttachType == AttachmentType::Screen; } +//////////////////////////////////////////////////////////////////////// +// Utils + +static void +RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples, + GLenum aInternalFormat, const gfx::IntSize& aSize) +{ + if (aSamples) { + aGL->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, + aSamples, + aInternalFormat, + aSize.width, aSize.height); + } else { + aGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, + aInternalFormat, + aSize.width, aSize.height); + } +} + +static GLuint +CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples, + const gfx::IntSize& aSize) +{ + GLuint rb = 0; + aGL->fGenRenderbuffers(1, &rb); + ScopedBindRenderbuffer autoRB(aGL, rb); + + RenderbufferStorageBySamples(aGL, aSamples, aFormat, aSize); + + return rb; +} + +static void +CreateRenderbuffersForOffscreen(GLContext* aGL, const GLFormats& aFormats, + const gfx::IntSize& aSize, bool aMultisample, + GLuint* aColorMSRB, GLuint* aDepthRB, + GLuint* aStencilRB) +{ + GLsizei samples = aMultisample ? aFormats.samples : 0; + if (aColorMSRB) { + MOZ_ASSERT(aFormats.samples > 0); + MOZ_ASSERT(aFormats.color_rbFormat); + + GLenum colorFormat = aFormats.color_rbFormat; + if (aGL->IsANGLE()) { + MOZ_ASSERT(colorFormat == LOCAL_GL_RGBA8); + colorFormat = LOCAL_GL_BGRA8_EXT; + } + + *aColorMSRB = CreateRenderbuffer(aGL, colorFormat, samples, aSize); + } + + if (aDepthRB && + aStencilRB && + aFormats.depthStencil) + { + *aDepthRB = CreateRenderbuffer(aGL, aFormats.depthStencil, samples, aSize); + *aStencilRB = *aDepthRB; + } else { + if (aDepthRB) { + MOZ_ASSERT(aFormats.depth); + + *aDepthRB = CreateRenderbuffer(aGL, aFormats.depth, samples, aSize); + } + + if (aStencilRB) { + MOZ_ASSERT(aFormats.stencil); + + *aStencilRB = CreateRenderbuffer(aGL, aFormats.stencil, samples, aSize); + } + } +} + //////////////////////////////////////////////////////////////////////// // DrawBuffer diff --git a/gfx/gl/GLScreenBuffer.h b/gfx/gl/GLScreenBuffer.h index 760224ab5e..15edad6925 100644 --- a/gfx/gl/GLScreenBuffer.h +++ b/gfx/gl/GLScreenBuffer.h @@ -26,7 +26,7 @@ namespace mozilla { namespace layers { class SharedSurfaceTextureClient; -} +} // namespace layers namespace gl { diff --git a/gfx/gl/SharedSurfaceANGLE.cpp b/gfx/gl/SharedSurfaceANGLE.cpp index 607f743959..3410540e77 100644 --- a/gfx/gl/SharedSurfaceANGLE.cpp +++ b/gfx/gl/SharedSurfaceANGLE.cpp @@ -41,17 +41,14 @@ CreatePBufferSurface(GLLibraryEGL* egl, } /*static*/ UniquePtr -SharedSurface_ANGLEShareHandle::Create(GLContext* gl, - EGLContext context, EGLConfig config, +SharedSurface_ANGLEShareHandle::Create(GLContext* gl, EGLConfig config, const gfx::IntSize& size, bool hasAlpha) { GLLibraryEGL* egl = &sEGLLibrary; MOZ_ASSERT(egl); MOZ_ASSERT(egl->IsExtensionSupported( GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle)); - - if (!context || !config) - return nullptr; + MOZ_ASSERT(config); EGLDisplay display = egl->Display(); EGLSurface pbuffer = CreatePBufferSurface(egl, display, config, size); @@ -82,8 +79,8 @@ SharedSurface_ANGLEShareHandle::Create(GLContext* gl, } typedef SharedSurface_ANGLEShareHandle ptrT; - UniquePtr ret( new ptrT(gl, egl, size, hasAlpha, context, - pbuffer, shareHandle, keyedMutex, fence) ); + UniquePtr ret( new ptrT(gl, egl, size, hasAlpha, pbuffer, shareHandle, + keyedMutex, fence) ); return Move(ret); } @@ -97,7 +94,6 @@ SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle(GLContext* gl, GLLibraryEGL* egl, const gfx::IntSize& size, bool hasAlpha, - EGLContext context, EGLSurface pbuffer, HANDLE shareHandle, const RefPtr& keyedMutex, @@ -109,7 +105,6 @@ SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle(GLContext* gl, hasAlpha, true) , mEGL(egl) - , mContext(context) , mPBuffer(pbuffer) , mShareHandle(shareHandle) , mKeyedMutex(keyedMutex) @@ -283,137 +278,6 @@ SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor(layers::SurfaceDescriptor* c //////////////////////////////////////////////////////////////////////////////// // Factory -static void -FillPBufferAttribs_ByBits(nsTArray& aAttrs, - int redBits, int greenBits, - int blueBits, int alphaBits, - int depthBits, int stencilBits) -{ - aAttrs.Clear(); - -#if defined(A1) || defined(A2) -#error The temp-macro names we want are already defined. -#endif - -#define A1(_x) do { aAttrs.AppendElement(_x); } while (0) -#define A2(_x,_y) do { A1(_x); A1(_y); } while (0) - - A2(LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT); - A2(LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT); - - A2(LOCAL_EGL_RED_SIZE, redBits); - A2(LOCAL_EGL_GREEN_SIZE, greenBits); - A2(LOCAL_EGL_BLUE_SIZE, blueBits); - A2(LOCAL_EGL_ALPHA_SIZE, alphaBits); - - A2(LOCAL_EGL_DEPTH_SIZE, depthBits); - A2(LOCAL_EGL_STENCIL_SIZE, stencilBits); - - A1(LOCAL_EGL_NONE); -#undef A1 -#undef A2 -} - -static void -FillPBufferAttribs_BySizes(nsTArray& attribs, - bool bpp16, bool hasAlpha, - int depthBits, int stencilBits) -{ - int red = 0; - int green = 0; - int blue = 0; - int alpha = 0; - - if (bpp16) { - if (hasAlpha) { - red = green = blue = alpha = 4; - } else { - red = 5; - green = 6; - blue = 5; - } - } else { - red = green = blue = 8; - if (hasAlpha) - alpha = 8; - } - - FillPBufferAttribs_ByBits(attribs, red, green, blue, alpha, depthBits, - stencilBits); -} - -static bool -DoesAttribBitsMatchCapBool(GLLibraryEGL* egl, EGLConfig config, EGLint attrib, - bool capBool) -{ - EGLint bits = 0; - egl->fGetConfigAttrib(egl->Display(), config, attrib, &bits); - MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS); - - bool hasBits = !!bits; - - return hasBits == capBool; -} - -static EGLConfig -ChooseConfig(GLContext* gl, GLLibraryEGL* egl, const SurfaceCaps& caps) -{ - MOZ_ASSERT(egl); - MOZ_ASSERT(caps.color); - - // We might want 24-bit depth, but we're only (fairly) sure to get 16-bit. - int depthBits = caps.depth ? 16 : 0; - int stencilBits = caps.stencil ? 8 : 0; - - // Ok, now we have everything. - nsTArray attribs(32); - FillPBufferAttribs_BySizes(attribs, caps.bpp16, caps.alpha, depthBits, - stencilBits); - - // Time to try to get this config: - EGLConfig configs[64]; - int numConfigs = sizeof(configs)/sizeof(EGLConfig); - int foundConfigs = 0; - - if (!egl->fChooseConfig(egl->Display(), attribs.Elements(), configs, - numConfigs, &foundConfigs) || - !foundConfigs) - { - NS_WARNING("No configs found for the requested formats."); - return EGL_NO_CONFIG; - } - - // The requests passed to ChooseConfig are treated as minimums. If you ask - // for 0 bits of alpha, we might still get 8 bits. - EGLConfig config = EGL_NO_CONFIG; - for (int i = 0; i < foundConfigs; i++) { - EGLConfig cur = configs[i]; - if (!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_ALPHA_SIZE, - caps.alpha) || - !DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_DEPTH_SIZE, - caps.depth) || - !DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_STENCIL_SIZE, - caps.stencil)) - { - continue; - } - - config = cur; - break; - } - - if (config == EGL_NO_CONFIG) { - NS_WARNING("No acceptable EGLConfig found."); - return EGL_NO_CONFIG; - } - - if (gl->DebugMode()) { - egl->DumpEGLConfig(config); - } - - return config; -} - /*static*/ UniquePtr SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl, const SurfaceCaps& caps, const RefPtr& allocator, @@ -427,13 +291,10 @@ SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl, const SurfaceCaps& caps, if (!egl->IsExtensionSupported(ext)) return nullptr; - bool success; + EGLConfig config = GLContextEGL::Cast(gl)->mConfig; + typedef SurfaceFactory_ANGLEShareHandle ptrT; - UniquePtr ret( new ptrT(gl, caps, allocator, flags, egl, &success) ); - - if (!success) - return nullptr; - + UniquePtr ret( new ptrT(gl, caps, allocator, flags, egl, config) ); return Move(ret); } @@ -442,22 +303,12 @@ SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl, const RefPtr& allocator, const layers::TextureFlags& flags, GLLibraryEGL* egl, - bool* const out_success) + EGLConfig config) : SurfaceFactory(SharedSurfaceType::EGLSurfaceANGLE, gl, caps, allocator, flags) , mProdGL(gl) , mEGL(egl) -{ - MOZ_ASSERT(out_success); - *out_success = false; - - mContext = GLContextEGL::Cast(mProdGL)->GetEGLContext(); - mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps); - if (mConfig == EGL_NO_CONFIG) - return; - - MOZ_ASSERT(mConfig && mContext); - *out_success = true; -} + , mConfig(config) +{ } } /* namespace gl */ } /* namespace mozilla */ diff --git a/gfx/gl/SharedSurfaceANGLE.h b/gfx/gl/SharedSurfaceANGLE.h index 65af53fea3..3dcab9d043 100644 --- a/gfx/gl/SharedSurfaceANGLE.h +++ b/gfx/gl/SharedSurfaceANGLE.h @@ -23,7 +23,6 @@ class SharedSurface_ANGLEShareHandle { public: static UniquePtr Create(GLContext* gl, - EGLContext context, EGLConfig config, const gfx::IntSize& size, bool hasAlpha); @@ -36,7 +35,6 @@ public: protected: GLLibraryEGL* const mEGL; - const EGLContext mContext; const EGLSurface mPBuffer; public: const HANDLE mShareHandle; @@ -51,7 +49,6 @@ protected: GLLibraryEGL* egl, const gfx::IntSize& size, bool hasAlpha, - EGLContext context, EGLSurface pbuffer, HANDLE shareHandle, const RefPtr& keyedMutex, @@ -94,8 +91,7 @@ class SurfaceFactory_ANGLEShareHandle protected: GLContext* const mProdGL; GLLibraryEGL* const mEGL; - EGLContext mContext; - EGLConfig mConfig; + const EGLConfig mConfig; public: static UniquePtr Create(GLContext* gl, @@ -107,13 +103,11 @@ protected: SurfaceFactory_ANGLEShareHandle(GLContext* gl, const SurfaceCaps& caps, const RefPtr& allocator, const layers::TextureFlags& flags, GLLibraryEGL* egl, - bool* const out_success); + EGLConfig config); virtual UniquePtr CreateShared(const gfx::IntSize& size) override { bool hasAlpha = mReadCaps.alpha; - return SharedSurface_ANGLEShareHandle::Create(mProdGL, - mContext, mConfig, - size, hasAlpha); + return SharedSurface_ANGLEShareHandle::Create(mProdGL, mConfig, size, hasAlpha); } }; diff --git a/gfx/gl/SharedSurfaceEGL.cpp b/gfx/gl/SharedSurfaceEGL.cpp index 9c5b99be62..ca3f18dfb2 100644 --- a/gfx/gl/SharedSurfaceEGL.cpp +++ b/gfx/gl/SharedSurfaceEGL.cpp @@ -220,7 +220,7 @@ SurfaceFactory_EGLImage::Create(GLContext* prodGL, const SurfaceCaps& caps, const RefPtr& allocator, const layers::TextureFlags& flags) { - EGLContext context = GLContextEGL::Cast(prodGL)->GetEGLContext(); + EGLContext context = GLContextEGL::Cast(prodGL)->mContext; typedef SurfaceFactory_EGLImage ptrT; UniquePtr ret; diff --git a/gfx/gl/SharedSurfaceGL.cpp b/gfx/gl/SharedSurfaceGL.cpp index 4cce70b82d..5aa7d2cb3b 100644 --- a/gfx/gl/SharedSurfaceGL.cpp +++ b/gfx/gl/SharedSurfaceGL.cpp @@ -27,10 +27,7 @@ SharedSurface_Basic::Create(GLContext* gl, gl->MakeCurrent(); GLContext::LocalErrorScope localError(*gl); - GLuint tex = CreateTexture(gl, formats.color_texInternalFormat, - formats.color_texFormat, - formats.color_texType, - size); + GLuint tex = CreateTextureForOffscreen(gl, formats, size); GLenum err = localError.GetError(); MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY); diff --git a/gfx/gl/moz.build b/gfx/gl/moz.build index 7db4fa7d6d..6461d5d741 100644 --- a/gfx/gl/moz.build +++ b/gfx/gl/moz.build @@ -71,7 +71,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': 'WGLLibrary.h', ] UNIFIED_SOURCES += [ - 'GLContextProviderEGL.cpp', + 'GLContextProviderWGL.cpp', 'SharedSurfaceANGLE.cpp', ] if CONFIG['MOZ_ENABLE_SKIA_GPU']: @@ -113,10 +113,6 @@ elif gl_provider == 'GLX': EXPORTS += [ 'SharedSurfaceGLX.h' ] -else: - UNIFIED_SOURCES += [ - 'GLContextProvider%s.cpp' % gl_provider, - ] UNIFIED_SOURCES += [ 'AndroidNativeWindow.cpp', @@ -127,6 +123,7 @@ UNIFIED_SOURCES += [ 'GLBlitHelper.cpp', 'GLContext.cpp', 'GLContextFeatures.cpp', + 'GLContextProviderEGL.cpp', 'GLContextTypes.cpp', 'GLDebugUtils.cpp', 'GLLibraryEGL.cpp', @@ -153,9 +150,12 @@ if CONFIG['MOZ_D3DCOMPILER_VISTA_DLL']: if CONFIG['MOZ_D3DCOMPILER_XP_DLL']: DEFINES['MOZ_D3DCOMPILER_XP_DLL'] = CONFIG['MOZ_D3DCOMPILER_XP_DLL'] -LOCAL_INCLUDES += CONFIG['SKIA_INCLUDES'] - CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS'] CXXFLAGS += CONFIG['TK_CFLAGS'] CFLAGS += CONFIG['MOZ_CAIRO_CFLAGS'] CFLAGS += CONFIG['TK_CFLAGS'] + +LOCAL_INCLUDES += CONFIG['SKIA_INCLUDES'] + +if CONFIG['OS_ARCH'] == 'WINNT': + del DEFINES['UNICODE'] diff --git a/gfx/thebes/gfxFT2FontList.cpp b/gfx/thebes/gfxFT2FontList.cpp index 6a38d17017..4433fb4ce6 100644 --- a/gfx/thebes/gfxFT2FontList.cpp +++ b/gfx/thebes/gfxFT2FontList.cpp @@ -1144,7 +1144,7 @@ gfxFT2FontList::FindFonts() gfxFontCache *fc = gfxFontCache::GetCache(); if (fc) fc->AgeAllGenerations(); - mPrefFonts.Clear(); + ClearLangGroupPrefFonts(); mCodepointsWithNoFonts.reset(); mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 5f66861cb0..6c228759da 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -410,6 +410,7 @@ public: uint32_t fallbackSystem; uint32_t textrunConst; uint32_t textrunDestr; + uint32_t genericLookups; }; uint32_t reflowCount; @@ -443,6 +444,7 @@ public: cumulative.fallbackSystem += current.fallbackSystem; cumulative.textrunConst += current.textrunConst; cumulative.textrunDestr += current.textrunDestr; + cumulative.genericLookups += current.genericLookups; memset(¤t, 0, sizeof(current)); } }; diff --git a/gfx/thebes/gfxFontConstants.h b/gfx/thebes/gfxFontConstants.h index 31d038ba69..1ed31e47d0 100644 --- a/gfx/thebes/gfxFontConstants.h +++ b/gfx/thebes/gfxFontConstants.h @@ -210,4 +210,16 @@ enum { #define NS_FONT_SUB_SUPER_SMALL_SIZE (20.0) #define NS_FONT_SUB_SUPER_LARGE_SIZE (45.0) +// pref lang id's for font prefs +enum eFontPrefLang { + #define FONT_PREF_LANG(enum_id_, str_, atom_id_) eFontPrefLang_ ## enum_id_ + #include "gfxFontPrefLangList.h" + #undef FONT_PREF_LANG + + , eFontPrefLang_CJKSet // special code for CJK set + , eFontPrefLang_First = eFontPrefLang_Western + , eFontPrefLang_Last = eFontPrefLang_Others + , eFontPrefLang_Count = (eFontPrefLang_Last - eFontPrefLang_First + 1) +}; + #endif diff --git a/gfx/thebes/gfxFontEntry.cpp b/gfx/thebes/gfxFontEntry.cpp index 3e1cbfa36d..0596580d37 100644 --- a/gfx/thebes/gfxFontEntry.cpp +++ b/gfx/thebes/gfxFontEntry.cpp @@ -1334,9 +1334,9 @@ gfxFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle, uint32_t minDistance = 0xffffffff; gfxFontEntry* matched = nullptr; - // iterate in reverse order so that the last-defined font is the first one - // in the fontlist used for matching, as per CSS Fonts spec - for (int32_t i = count - 1; i >= 0; i--) { + // iterate in forward order so that faces like 'Bold' are matched before + // matching style distance faces such as 'Bold Outline' (see bug 1185812) + for (uint32_t i = 0; i < count; i++) { fe = mAvailableFonts[i]; uint32_t distance = WeightDistance(aFontStyle.weight, fe->Weight()) + diff --git a/gfx/thebes/gfxFontFamilyList.h b/gfx/thebes/gfxFontFamilyList.h index 6bd7c47001..94bc95bc2a 100644 --- a/gfx/thebes/gfxFontFamilyList.h +++ b/gfx/thebes/gfxFontFamilyList.h @@ -29,7 +29,7 @@ enum FontFamilyType { eFamily_named_quoted, // generics - eFamily_serif, + eFamily_serif, // pref font code relies on this ordering!!! eFamily_sans_serif, eFamily_monospace, eFamily_cursive, @@ -37,7 +37,11 @@ enum FontFamilyType { // special eFamily_moz_variable, - eFamily_moz_fixed + eFamily_moz_fixed, + + eFamily_generic_first = eFamily_serif, + eFamily_generic_last = eFamily_fantasy, + eFamily_generic_count = (eFamily_fantasy - eFamily_serif + 1) }; enum QuotedName { eQuotedName, eUnquotedName }; diff --git a/gfx/thebes/gfxFontconfigFonts.cpp b/gfx/thebes/gfxFontconfigFonts.cpp index 5ce08ce503..7255777d08 100644 --- a/gfx/thebes/gfxFontconfigFonts.cpp +++ b/gfx/thebes/gfxFontconfigFonts.cpp @@ -25,6 +25,9 @@ #include "gfxFontconfigUtils.h" #include "gfxUserFontSet.h" #include "gfxFontConstants.h" +#include "nsGkAtoms.h" +#include "nsILanguageAtomService.h" +#include "nsServiceManagerUtils.h" #include #include @@ -1281,9 +1284,140 @@ gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle) } void -gfxPangoFontGroup::FindPlatformFont(const nsAString& fontName, - bool aUseFontSet, - void *aClosure) +gfxPangoFontGroup::FindGenericFontsPFG(FontFamilyType aGenericType, + nsIAtom *aLanguage, + void *aClosure) +{ + nsAutoTArray resolvedGenerics; + ResolveGenericFontNamesPFG(aGenericType, aLanguage, resolvedGenerics); + uint32_t g = 0, numGenerics = resolvedGenerics.Length(); + for (g = 0; g < numGenerics; g++) { + FindPlatformFontPFG(resolvedGenerics[g], false, aClosure); + } +} + +/* static */ void +gfxPangoFontGroup::ResolveGenericFontNamesPFG(FontFamilyType aGenericType, + nsIAtom *aLanguage, + nsTArray& aGenericFamilies) +{ + static const char kGeneric_serif[] = "serif"; + static const char kGeneric_sans_serif[] = "sans-serif"; + static const char kGeneric_monospace[] = "monospace"; + static const char kGeneric_cursive[] = "cursive"; + static const char kGeneric_fantasy[] = "fantasy"; + + // treat -moz-fixed as monospace + if (aGenericType == eFamily_moz_fixed) { + aGenericType = eFamily_monospace; + } + + // type should be standard generic type at this point + NS_ASSERTION(aGenericType >= eFamily_serif && + aGenericType <= eFamily_fantasy, + "standard generic font family type required"); + + // create the lang string + nsIAtom *langGroupAtom = nullptr; + nsAutoCString langGroupString; + if (aLanguage) { + if (!gLangService) { + CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService); + } + if (gLangService) { + nsresult rv; + langGroupAtom = gLangService->GetLanguageGroup(aLanguage, &rv); + } + } + if (!langGroupAtom) { + langGroupAtom = nsGkAtoms::Unicode; + } + langGroupAtom->ToUTF8String(langGroupString); + + // map generic type to string + const char *generic = nullptr; + switch (aGenericType) { + case eFamily_serif: + generic = kGeneric_serif; + break; + case eFamily_sans_serif: + generic = kGeneric_sans_serif; + break; + case eFamily_monospace: + generic = kGeneric_monospace; + break; + case eFamily_cursive: + generic = kGeneric_cursive; + break; + case eFamily_fantasy: + generic = kGeneric_fantasy; + break; + default: + break; + } + + if (!generic) { + return; + } + + aGenericFamilies.Clear(); + + // load family for "font.name.generic.lang" + nsAutoCString prefFontName("font.name."); + prefFontName.Append(generic); + prefFontName.Append('.'); + prefFontName.Append(langGroupString); + gfxFontUtils::AppendPrefsFontList(prefFontName.get(), + aGenericFamilies); + + // if lang has pref fonts, also load fonts for "font.name-list.generic.lang" + if (!aGenericFamilies.IsEmpty()) { + nsAutoCString prefFontListName("font.name-list."); + prefFontListName.Append(generic); + prefFontListName.Append('.'); + prefFontListName.Append(langGroupString); + gfxFontUtils::AppendPrefsFontList(prefFontListName.get(), + aGenericFamilies); + } + +#if 0 // dump out generic mappings + printf("%s ===> ", prefFontName.get()); + for (uint32_t k = 0; k < aGenericFamilies.Length(); k++) { + if (k > 0) printf(", "); + printf("%s", NS_ConvertUTF16toUTF8(aGenericFamilies[k]).get()); + } + printf("\n"); +#endif +} + +void gfxPangoFontGroup::EnumerateFontListPFG(nsIAtom *aLanguage, void *aClosure) +{ + // initialize fonts in the font family list + const nsTArray& fontlist = mFamilyList.GetFontlist(); + + // lookup fonts in the fontlist + uint32_t i, numFonts = fontlist.Length(); + for (i = 0; i < numFonts; i++) { + const FontFamilyName& name = fontlist[i]; + if (name.IsNamed()) { + FindPlatformFontPFG(name.mName, true, aClosure); + } else { + FindGenericFontsPFG(name.mType, aLanguage, aClosure); + } + } + + // if necessary, append default generic onto the end + if (mFamilyList.GetDefaultFontType() != eFamily_none && + !mFamilyList.HasDefaultGeneric()) { + FindGenericFontsPFG(mFamilyList.GetDefaultFontType(), + aLanguage, aClosure); + } +} + +void +gfxPangoFontGroup::FindPlatformFontPFG(const nsAString& fontName, + bool aUseFontSet, + void *aClosure) { nsTArray *list = static_cast*>(aClosure); @@ -1360,8 +1494,8 @@ gfxPangoFontGroup::MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor, } nsAutoTArray fcFamilyList; - EnumerateFontList(langGroup ? langGroup.get() : mStyle.language.get(), - &fcFamilyList); + EnumerateFontListPFG(langGroup ? langGroup.get() : mStyle.language.get(), + &fcFamilyList); // To consider: A fontset cache here could be helpful. diff --git a/gfx/thebes/gfxFontconfigFonts.h b/gfx/thebes/gfxFontconfigFonts.h index 44d9a7c248..1a7c1dbf3b 100644 --- a/gfx/thebes/gfxFontconfigFonts.h +++ b/gfx/thebes/gfxFontconfigFonts.h @@ -94,9 +94,27 @@ private: return mSizeAdjustFactor; } - virtual void FindPlatformFont(const nsAString& aName, - bool aUseFontSet, - void *aClosure); + // old helper methods from gfxFontGroup, moved here so that those methods + // can be revamped without affecting the legacy code here + + // iterate over the fontlist, lookup names and expand generics + void EnumerateFontListPFG(nsIAtom *aLanguage, void *aClosure); + + // expand a generic to a list of specific names based on prefs + void FindGenericFontsPFG(mozilla::FontFamilyType aGenericType, + nsIAtom *aLanguage, + void *aClosure); + + // lookup and add a font with a given name (i.e. *not* a generic!) + void FindPlatformFontPFG(const nsAString& aName, + bool aUseFontSet, + void *aClosure); + + static void + ResolveGenericFontNamesPFG(mozilla::FontFamilyType aGenericType, + nsIAtom *aLanguage, + nsTArray& aGenericFamilies); + friend class gfxSystemFcFontEntry; static FT_Library GetFTLibrary(); diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 12ecc273c8..411edea7d5 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -364,27 +364,6 @@ MemoryPressureObserver::Observe(nsISupports *aSubject, return NS_OK; } -// xxx - this can probably be eliminated by reworking pref font handling code -static const char *gPrefLangNames[] = { - #define FONT_PREF_LANG(enum_id_, str_, atom_id_) str_ - #include "gfxFontPrefLangList.h" - #undef FONT_PREF_LANG -}; - -static nsIAtom* PrefLangToLangGroups(uint32_t aIndex) -{ - // static array here avoids static constructor - static nsIAtom* gPrefLangToLangGroups[] = { - #define FONT_PREF_LANG(enum_id_, str_, atom_id_) nsGkAtoms::atom_id_ - #include "gfxFontPrefLangList.h" - #undef FONT_PREF_LANG - }; - - return aIndex < ArrayLength(gPrefLangToLangGroups) - ? gPrefLangToLangGroups[aIndex] - : nsGkAtoms::Unicode; -} - gfxPlatform::gfxPlatform() : mTileWidth(-1) , mTileHeight(-1) @@ -1364,160 +1343,6 @@ gfxPlatform::MakePlatformFont(const nsAString& aFontName, return nullptr; } -bool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArrayLen, PrefFontCallback aCallback, - void *aClosure) -{ - NS_ENSURE_TRUE(Preferences::GetRootBranch(), false); - - uint32_t i; - for (i = 0; i < aLangArrayLen; i++) { - eFontPrefLang prefLang = aLangArray[i]; - const char *langGroup = GetPrefLangName(prefLang); - - nsAutoCString prefName; - - prefName.AssignLiteral("font.default."); - prefName.Append(langGroup); - nsAdoptingCString genericDotLang = Preferences::GetCString(prefName.get()); - - genericDotLang.Append('.'); - genericDotLang.Append(langGroup); - - // fetch font.name.xxx value - prefName.AssignLiteral("font.name."); - prefName.Append(genericDotLang); - nsAdoptingCString nameValue = Preferences::GetCString(prefName.get()); - if (nameValue) { - if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(nameValue), aClosure)) - return false; - } - - // fetch font.name-list.xxx value - prefName.AssignLiteral("font.name-list."); - prefName.Append(genericDotLang); - nsAdoptingCString nameListValue = Preferences::GetCString(prefName.get()); - if (nameListValue && !nameListValue.Equals(nameValue)) { - const char kComma = ','; - const char *p, *p_end; - nsAutoCString list(nameListValue); - list.BeginReading(p); - list.EndReading(p_end); - while (p < p_end) { - while (nsCRT::IsAsciiSpace(*p)) { - if (++p == p_end) - break; - } - if (p == p_end) - break; - const char *start = p; - while (++p != p_end && *p != kComma) - /* nothing */ ; - nsAutoCString fontName(Substring(start, p)); - fontName.CompressWhitespace(false, true); - if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(fontName), aClosure)) - return false; - p++; - } - } - } - - return true; -} - -eFontPrefLang -gfxPlatform::GetFontPrefLangFor(const char* aLang) -{ - if (!aLang || !aLang[0]) { - return eFontPrefLang_Others; - } - for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); ++i) { - if (!PL_strcasecmp(gPrefLangNames[i], aLang)) { - return eFontPrefLang(i); - } - } - return eFontPrefLang_Others; -} - -eFontPrefLang -gfxPlatform::GetFontPrefLangFor(nsIAtom *aLang) -{ - if (!aLang) - return eFontPrefLang_Others; - nsAutoCString lang; - aLang->ToUTF8String(lang); - return GetFontPrefLangFor(lang.get()); -} - -nsIAtom* -gfxPlatform::GetLangGroupForPrefLang(eFontPrefLang aLang) -{ - // the special CJK set pref lang should be resolved into separate - // calls to individual CJK pref langs before getting here - NS_ASSERTION(aLang != eFontPrefLang_CJKSet, "unresolved CJK set pref lang"); - - return PrefLangToLangGroups(uint32_t(aLang)); -} - -const char* -gfxPlatform::GetPrefLangName(eFontPrefLang aLang) -{ - if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) { - return gPrefLangNames[uint32_t(aLang)]; - } - return nullptr; -} - -eFontPrefLang -gfxPlatform::GetFontPrefLangFor(uint8_t aUnicodeRange) -{ - switch (aUnicodeRange) { - case kRangeSetLatin: return eFontPrefLang_Western; - case kRangeCyrillic: return eFontPrefLang_Cyrillic; - case kRangeGreek: return eFontPrefLang_Greek; - case kRangeHebrew: return eFontPrefLang_Hebrew; - case kRangeArabic: return eFontPrefLang_Arabic; - case kRangeThai: return eFontPrefLang_Thai; - case kRangeKorean: return eFontPrefLang_Korean; - case kRangeJapanese: return eFontPrefLang_Japanese; - case kRangeSChinese: return eFontPrefLang_ChineseCN; - case kRangeTChinese: return eFontPrefLang_ChineseTW; - case kRangeDevanagari: return eFontPrefLang_Devanagari; - case kRangeTamil: return eFontPrefLang_Tamil; - case kRangeArmenian: return eFontPrefLang_Armenian; - case kRangeBengali: return eFontPrefLang_Bengali; - case kRangeCanadian: return eFontPrefLang_Canadian; - case kRangeEthiopic: return eFontPrefLang_Ethiopic; - case kRangeGeorgian: return eFontPrefLang_Georgian; - case kRangeGujarati: return eFontPrefLang_Gujarati; - case kRangeGurmukhi: return eFontPrefLang_Gurmukhi; - case kRangeKhmer: return eFontPrefLang_Khmer; - case kRangeMalayalam: return eFontPrefLang_Malayalam; - case kRangeOriya: return eFontPrefLang_Oriya; - case kRangeTelugu: return eFontPrefLang_Telugu; - case kRangeKannada: return eFontPrefLang_Kannada; - case kRangeSinhala: return eFontPrefLang_Sinhala; - case kRangeTibetan: return eFontPrefLang_Tibetan; - case kRangeSetCJK: return eFontPrefLang_CJKSet; - default: return eFontPrefLang_Others; - } -} - -bool -gfxPlatform::IsLangCJK(eFontPrefLang aLang) -{ - switch (aLang) { - case eFontPrefLang_Japanese: - case eFontPrefLang_ChineseTW: - case eFontPrefLang_ChineseCN: - case eFontPrefLang_ChineseHK: - case eFontPrefLang_Korean: - case eFontPrefLang_CJKSet: - return true; - default: - return false; - } -} - mozilla::layers::DiagnosticTypes gfxPlatform::GetLayerDiagnosticTypes() { @@ -1537,143 +1362,6 @@ gfxPlatform::GetLayerDiagnosticTypes() return type; } -void -gfxPlatform::GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang) -{ - if (IsLangCJK(aCharLang)) { - AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang); - } else { - AppendPrefLang(aPrefLangs, aLen, aCharLang); - } - - AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others); -} - -void -gfxPlatform::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang) -{ - // prefer the lang specified by the page *if* CJK - if (IsLangCJK(aPageLang)) { - AppendPrefLang(aPrefLangs, aLen, aPageLang); - } - - // if not set up, set up the default CJK order, based on accept lang settings and locale - if (mCJKPrefLangs.Length() == 0) { - - // temp array - eFontPrefLang tempPrefLangs[kMaxLenPrefLangList]; - uint32_t tempLen = 0; - - // Add the CJK pref fonts from accept languages, the order should be same order - nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages"); - if (!list.IsEmpty()) { - const char kComma = ','; - const char *p, *p_end; - list.BeginReading(p); - list.EndReading(p_end); - while (p < p_end) { - while (nsCRT::IsAsciiSpace(*p)) { - if (++p == p_end) - break; - } - if (p == p_end) - break; - const char *start = p; - while (++p != p_end && *p != kComma) - /* nothing */ ; - nsAutoCString lang(Substring(start, p)); - lang.CompressWhitespace(false, true); - eFontPrefLang fpl = gfxPlatform::GetFontPrefLangFor(lang.get()); - switch (fpl) { - case eFontPrefLang_Japanese: - case eFontPrefLang_Korean: - case eFontPrefLang_ChineseCN: - case eFontPrefLang_ChineseHK: - case eFontPrefLang_ChineseTW: - AppendPrefLang(tempPrefLangs, tempLen, fpl); - break; - default: - break; - } - p++; - } - } - - do { // to allow 'break' to abort this block if a call fails - nsresult rv; - nsCOMPtr ls = - do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv); - if (NS_FAILED(rv)) - break; - - nsCOMPtr appLocale; - rv = ls->GetApplicationLocale(getter_AddRefs(appLocale)); - if (NS_FAILED(rv)) - break; - - nsString localeStr; - rv = appLocale-> - GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr); - if (NS_FAILED(rv)) - break; - - const nsAString& lang = Substring(localeStr, 0, 2); - if (lang.EqualsLiteral("ja")) { - AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese); - } else if (lang.EqualsLiteral("zh")) { - const nsAString& region = Substring(localeStr, 3, 2); - if (region.EqualsLiteral("CN")) { - AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN); - } else if (region.EqualsLiteral("TW")) { - AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW); - } else if (region.EqualsLiteral("HK")) { - AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK); - } - } else if (lang.EqualsLiteral("ko")) { - AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean); - } - } while (0); - - // last resort... (the order is same as old gfx.) - AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese); - AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean); - AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN); - AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK); - AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW); - - // copy into the cached array - uint32_t j; - for (j = 0; j < tempLen; j++) { - mCJKPrefLangs.AppendElement(tempPrefLangs[j]); - } - } - - // append in cached CJK langs - uint32_t i, numCJKlangs = mCJKPrefLangs.Length(); - - for (i = 0; i < numCJKlangs; i++) { - AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i])); - } - -} - -void -gfxPlatform::AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang) -{ - if (aLen >= kMaxLenPrefLangList) return; - - // make sure - uint32_t i = 0; - while (i < aLen && aPrefLangs[i] != aAddLang) { - i++; - } - - if (i == aLen) { - aPrefLangs[aLen] = aAddLang; - aLen++; - } -} - void gfxPlatform::InitBackendPrefs(uint32_t aCanvasBitmask, BackendType aCanvasDefault, uint32_t aContentBitmask, BackendType aContentDefault) diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 761edee2e4..2a9e61dc8c 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -70,15 +70,6 @@ BackendTypeBit(BackendType b) extern cairo_user_data_key_t kDrawTarget; -// pref lang id's for font prefs -enum eFontPrefLang { - #define FONT_PREF_LANG(enum_id_, str_, atom_id_) eFontPrefLang_ ## enum_id_ - #include "gfxFontPrefLangList.h" - #undef FONT_PREF_LANG - - , eFontPrefLang_CJKSet // special code for CJK set -}; - enum eCMSMode { eCMSMode_Off = 0, // No color management eCMSMode_All = 1, // Color manage everything @@ -436,41 +427,6 @@ public: virtual bool DidRenderingDeviceReset(DeviceResetReason* aResetReason = nullptr) { return false; } - // in some situations, need to make decisions about ambiguous characters, may need to look at multiple pref langs - void GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang); - - /** - * Iterate over pref fonts given a list of lang groups. For a single lang - * group, multiple pref fonts are possible. If error occurs, returns false, - * true otherwise. Callback returns false to abort process. - */ - typedef bool (*PrefFontCallback) (eFontPrefLang aLang, const nsAString& aName, - void *aClosure); - static bool ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArrayLen, - PrefFontCallback aCallback, - void *aClosure); - - // convert a lang group to enum constant (i.e. "zh-TW" ==> eFontPrefLang_ChineseTW) - static eFontPrefLang GetFontPrefLangFor(const char* aLang); - - // convert a lang group atom to enum constant - static eFontPrefLang GetFontPrefLangFor(nsIAtom *aLang); - - // convert an enum constant to a lang group atom - static nsIAtom* GetLangGroupForPrefLang(eFontPrefLang aLang); - - // convert a enum constant to lang group string (i.e. eFontPrefLang_ChineseTW ==> "zh-TW") - static const char* GetPrefLangName(eFontPrefLang aLang); - - // map a Unicode range (based on char code) to a font language for Preferences - static eFontPrefLang GetFontPrefLangFor(uint8_t aUnicodeRange); - - // returns true if a pref lang is CJK - static bool IsLangCJK(eFontPrefLang aLang); - - // helper method to add a pref lang to an array, if not already in array - static void AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang); - // returns a list of commonly used fonts for a given character // these are *possible* matches, no cmap-checking is done at this level virtual void GetCommonFallbackFonts(uint32_t /*aCh*/, uint32_t /*aNextCh*/, @@ -677,9 +633,6 @@ protected: gfxPlatform(); virtual ~gfxPlatform(); - void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, - eFontPrefLang aCharLang, eFontPrefLang aPageLang); - /** * Initialized hardware vsync based on each platform. */ @@ -794,7 +747,6 @@ private: void PopulateScreenInfo(); nsRefPtr mScreenReferenceSurface; - nsTArray mCJKPrefLangs; nsCOMPtr mSRGBOverrideObserver; nsCOMPtr mFontPrefsObserver; nsCOMPtr mMemoryPressureObserver; diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index 84ddaddef2..95e10665d2 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -9,6 +9,10 @@ #include "gfxTextRun.h" #include "gfxUserFontSet.h" +#include "nsCRT.h" +#include "nsGkAtoms.h" +#include "nsILocaleService.h" +#include "nsServiceManagerUtils.h" #include "nsUnicharUtils.h" #include "nsUnicodeRange.h" #include "nsUnicodeProperties.h" @@ -94,6 +98,16 @@ static const char* kObservedPrefs[] = { nullptr }; +// xxx - this can probably be eliminated by reworking pref font handling code +static const char *gPrefLangNames[] = { + #define FONT_PREF_LANG(enum_id_, str_, atom_id_) str_ + #include "gfxFontPrefLangList.h" + #undef FONT_PREF_LANG +}; + +static_assert(MOZ_ARRAY_LENGTH(gPrefLangNames) == uint32_t(eFontPrefLang_Count), + "size of pref lang name array doesn't match pref lang enum size"); + class gfxFontListPrefObserver final : public nsIObserver { ~gfxFontListPrefObserver() {} public: @@ -113,7 +127,7 @@ gfxFontListPrefObserver::Observe(nsISupports *aSubject, NS_ASSERTION(!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID), "invalid topic"); // XXX this could be made to only clear out the cache for the prefs that were changed // but it probably isn't that big a deal. - gfxPlatformFontList::PlatformFontList()->ClearPrefFonts(); + gfxPlatformFontList::PlatformFontList()->ClearLangGroupPrefFonts(); gfxFontCache::GetCache()->AgeAllGenerations(); return NS_OK; } @@ -162,7 +176,7 @@ gfxPlatformFontList::MemoryReporter::CollectReports( gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames) : mFontFamilies(64), mOtherFamilyNames(16), - mPrefFonts(8), mBadUnderlineFamilyNames(8), mSharedCmaps(8), + mBadUnderlineFamilyNames(8), mSharedCmaps(8), mStartIndex(0), mIncrement(1), mNumFamilies(0), mFontlistInitCount(0) { mOtherFamilyNamesInitialized = false; @@ -187,11 +201,15 @@ gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames) gfxPlatformFontList::~gfxPlatformFontList() { mSharedCmaps.Clear(); + ClearLangGroupPrefFonts(); NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer"); Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs); NS_RELEASE(gFontListPrefObserver); } +// number of CSS generic font families +const uint32_t kNumGenerics = 5; + nsresult gfxPlatformFontList::InitFontList() { @@ -216,7 +234,7 @@ gfxPlatformFontList::InitFontList() mExtraNames->mPostscriptNames.Clear(); } mFaceNameListsInitialized = false; - mPrefFonts.Clear(); + ClearLangGroupPrefFonts(); mReplacementCharFallbackFamily = nullptr; CancelLoader(); @@ -703,18 +721,6 @@ gfxPlatformFontList::FindFontForFamily(const nsAString& aFamily, const gfxFontSt return nullptr; } -bool -gfxPlatformFontList::GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray > *array) -{ - return mPrefFonts.Get(uint32_t(aLangGroup), array); -} - -void -gfxPlatformFontList::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray >& array) -{ - mPrefFonts.Put(uint32_t(aLangGroup), array); -} - void gfxPlatformFontList::AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName) { @@ -801,6 +807,419 @@ gfxPlatformFontList::RemoveCmap(const gfxCharacterMap* aCharMap) } } +void +gfxPlatformFontList::ResolveGenericFontNames( + FontFamilyType aGenericType, + eFontPrefLang aPrefLang, + nsTArray>* aGenericFamilies +) +{ + const char* langGroupStr = GetPrefLangName(aPrefLang); + + static const char kGeneric_serif[] = "serif"; + static const char kGeneric_sans_serif[] = "sans-serif"; + static const char kGeneric_monospace[] = "monospace"; + static const char kGeneric_cursive[] = "cursive"; + static const char kGeneric_fantasy[] = "fantasy"; + + // type should be standard generic type at this point + NS_ASSERTION(aGenericType >= eFamily_serif && + aGenericType <= eFamily_fantasy, + "standard generic font family type required"); + + // map generic type to string + const char *generic = nullptr; + switch (aGenericType) { + case eFamily_serif: + generic = kGeneric_serif; + break; + case eFamily_sans_serif: + generic = kGeneric_sans_serif; + break; + case eFamily_monospace: + generic = kGeneric_monospace; + break; + case eFamily_cursive: + generic = kGeneric_cursive; + break; + case eFamily_fantasy: + generic = kGeneric_fantasy; + break; + default: + break; + } + + if (!generic) { + return; + } + + nsAutoTArray genericFamilies; + + // load family for "font.name.generic.lang" + nsAutoCString prefFontName("font.name."); + prefFontName.Append(generic); + prefFontName.Append('.'); + prefFontName.Append(langGroupStr); + gfxFontUtils::AppendPrefsFontList(prefFontName.get(), genericFamilies); + + // load fonts for "font.name-list.generic.lang" + nsAutoCString prefFontListName("font.name-list."); + prefFontListName.Append(generic); + prefFontListName.Append('.'); + prefFontListName.Append(langGroupStr); + gfxFontUtils::AppendPrefsFontList(prefFontListName.get(), genericFamilies); + + nsIAtom* langGroup = GetLangGroupForPrefLang(aPrefLang); + NS_ASSERTION(langGroup, "null lang group for pref lang"); + + // lookup and add platform fonts uniquely + for (const nsString& genericFamily : genericFamilies) { + nsRefPtr family = + FindFamily(genericFamily, langGroup, false); + if (family) { + bool notFound = true; + for (const gfxFontFamily* f : *aGenericFamilies) { + if (f == family) { + notFound = false; + break; + } + } + if (notFound) { + aGenericFamilies->AppendElement(family); + } + } + } + +#if 0 // dump out generic mappings + printf("%s ===> ", prefFontName.get()); + for (uint32_t k = 0; k < aGenericFamilies->Length(); k++) { + if (k > 0) printf(", "); + printf("%s", NS_ConvertUTF16toUTF8(aGenericFamilies[k]->Name()).get()); + } + printf("\n"); +#endif +} + +nsTArray>* +gfxPlatformFontList::GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType, + eFontPrefLang aPrefLang) +{ + // treat -moz-fixed as monospace + if (aGenericType == eFamily_moz_fixed) { + aGenericType = eFamily_monospace; + } + + PrefFontList* prefFonts = mLangGroupPrefFonts[aPrefLang][aGenericType]; + if (MOZ_UNLIKELY(!prefFonts)) { + prefFonts = new PrefFontList; + ResolveGenericFontNames(aGenericType, aPrefLang, prefFonts); + mLangGroupPrefFonts[aPrefLang][aGenericType] = prefFonts; + } + return prefFonts; +} + +void +gfxPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType, + nsIAtom* aLanguage, + nsTArray& aFamilyList) +{ + // map lang ==> langGroup + nsIAtom *langGroup = nullptr; + if (aLanguage) { + if (!mLangService) { + mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID); + } + if (mLangService) { + nsresult rv; + langGroup = mLangService->GetLanguageGroup(aLanguage, &rv); + } + } + if (!langGroup) { + langGroup = nsGkAtoms::Unicode; + } + + // langGroup ==> prefLang + eFontPrefLang prefLang = GetFontPrefLangFor(langGroup); + + // lookup pref fonts + nsTArray>* prefFonts = + GetPrefFontsLangGroup(aGenericType, prefLang); + + if (!prefFonts->IsEmpty()) { + aFamilyList.AppendElements(*prefFonts); + } +} + +static nsIAtom* PrefLangToLangGroups(uint32_t aIndex) +{ + // static array here avoids static constructor + static nsIAtom* gPrefLangToLangGroups[] = { + #define FONT_PREF_LANG(enum_id_, str_, atom_id_) nsGkAtoms::atom_id_ + #include "gfxFontPrefLangList.h" + #undef FONT_PREF_LANG + }; + + return aIndex < ArrayLength(gPrefLangToLangGroups) + ? gPrefLangToLangGroups[aIndex] + : nsGkAtoms::Unicode; +} + +eFontPrefLang +gfxPlatformFontList::GetFontPrefLangFor(const char* aLang) +{ + if (!aLang || !aLang[0]) { + return eFontPrefLang_Others; + } + for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); ++i) { + if (!PL_strcasecmp(gPrefLangNames[i], aLang)) { + return eFontPrefLang(i); + } + } + return eFontPrefLang_Others; +} + +eFontPrefLang +gfxPlatformFontList::GetFontPrefLangFor(nsIAtom *aLang) +{ + if (!aLang) + return eFontPrefLang_Others; + nsAutoCString lang; + aLang->ToUTF8String(lang); + return GetFontPrefLangFor(lang.get()); +} + +nsIAtom* +gfxPlatformFontList::GetLangGroupForPrefLang(eFontPrefLang aLang) +{ + // the special CJK set pref lang should be resolved into separate + // calls to individual CJK pref langs before getting here + NS_ASSERTION(aLang != eFontPrefLang_CJKSet, "unresolved CJK set pref lang"); + + return PrefLangToLangGroups(uint32_t(aLang)); +} + +const char* +gfxPlatformFontList::GetPrefLangName(eFontPrefLang aLang) +{ + if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) { + return gPrefLangNames[uint32_t(aLang)]; + } + return nullptr; +} + +eFontPrefLang +gfxPlatformFontList::GetFontPrefLangFor(uint8_t aUnicodeRange) +{ + switch (aUnicodeRange) { + case kRangeSetLatin: return eFontPrefLang_Western; + case kRangeCyrillic: return eFontPrefLang_Cyrillic; + case kRangeGreek: return eFontPrefLang_Greek; + case kRangeHebrew: return eFontPrefLang_Hebrew; + case kRangeArabic: return eFontPrefLang_Arabic; + case kRangeThai: return eFontPrefLang_Thai; + case kRangeKorean: return eFontPrefLang_Korean; + case kRangeJapanese: return eFontPrefLang_Japanese; + case kRangeSChinese: return eFontPrefLang_ChineseCN; + case kRangeTChinese: return eFontPrefLang_ChineseTW; + case kRangeDevanagari: return eFontPrefLang_Devanagari; + case kRangeTamil: return eFontPrefLang_Tamil; + case kRangeArmenian: return eFontPrefLang_Armenian; + case kRangeBengali: return eFontPrefLang_Bengali; + case kRangeCanadian: return eFontPrefLang_Canadian; + case kRangeEthiopic: return eFontPrefLang_Ethiopic; + case kRangeGeorgian: return eFontPrefLang_Georgian; + case kRangeGujarati: return eFontPrefLang_Gujarati; + case kRangeGurmukhi: return eFontPrefLang_Gurmukhi; + case kRangeKhmer: return eFontPrefLang_Khmer; + case kRangeMalayalam: return eFontPrefLang_Malayalam; + case kRangeOriya: return eFontPrefLang_Oriya; + case kRangeTelugu: return eFontPrefLang_Telugu; + case kRangeKannada: return eFontPrefLang_Kannada; + case kRangeSinhala: return eFontPrefLang_Sinhala; + case kRangeTibetan: return eFontPrefLang_Tibetan; + case kRangeSetCJK: return eFontPrefLang_CJKSet; + default: return eFontPrefLang_Others; + } +} + +bool +gfxPlatformFontList::IsLangCJK(eFontPrefLang aLang) +{ + switch (aLang) { + case eFontPrefLang_Japanese: + case eFontPrefLang_ChineseTW: + case eFontPrefLang_ChineseCN: + case eFontPrefLang_ChineseHK: + case eFontPrefLang_Korean: + case eFontPrefLang_CJKSet: + return true; + default: + return false; + } +} + +void +gfxPlatformFontList::GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang) +{ + if (IsLangCJK(aCharLang)) { + AppendCJKPrefLangs(aPrefLangs, aLen, aCharLang, aPageLang); + } else { + AppendPrefLang(aPrefLangs, aLen, aCharLang); + } + + AppendPrefLang(aPrefLangs, aLen, eFontPrefLang_Others); +} + +void +gfxPlatformFontList::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang) +{ + // prefer the lang specified by the page *if* CJK + if (IsLangCJK(aPageLang)) { + AppendPrefLang(aPrefLangs, aLen, aPageLang); + } + + // if not set up, set up the default CJK order, based on accept lang settings and locale + if (mCJKPrefLangs.Length() == 0) { + + // temp array + eFontPrefLang tempPrefLangs[kMaxLenPrefLangList]; + uint32_t tempLen = 0; + + // Add the CJK pref fonts from accept languages, the order should be same order + nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages"); + if (!list.IsEmpty()) { + const char kComma = ','; + const char *p, *p_end; + list.BeginReading(p); + list.EndReading(p_end); + while (p < p_end) { + while (nsCRT::IsAsciiSpace(*p)) { + if (++p == p_end) + break; + } + if (p == p_end) + break; + const char *start = p; + while (++p != p_end && *p != kComma) + /* nothing */ ; + nsAutoCString lang(Substring(start, p)); + lang.CompressWhitespace(false, true); + eFontPrefLang fpl = gfxPlatformFontList::GetFontPrefLangFor(lang.get()); + switch (fpl) { + case eFontPrefLang_Japanese: + case eFontPrefLang_Korean: + case eFontPrefLang_ChineseCN: + case eFontPrefLang_ChineseHK: + case eFontPrefLang_ChineseTW: + AppendPrefLang(tempPrefLangs, tempLen, fpl); + break; + default: + break; + } + p++; + } + } + + do { // to allow 'break' to abort this block if a call fails + nsresult rv; + nsCOMPtr ls = + do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) + break; + + nsCOMPtr appLocale; + rv = ls->GetApplicationLocale(getter_AddRefs(appLocale)); + if (NS_FAILED(rv)) + break; + + nsString localeStr; + rv = appLocale-> + GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr); + if (NS_FAILED(rv)) + break; + + const nsAString& lang = Substring(localeStr, 0, 2); + if (lang.EqualsLiteral("ja")) { + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese); + } else if (lang.EqualsLiteral("zh")) { + const nsAString& region = Substring(localeStr, 3, 2); + if (region.EqualsLiteral("CN")) { + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN); + } else if (region.EqualsLiteral("TW")) { + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW); + } else if (region.EqualsLiteral("HK")) { + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK); + } + } else if (lang.EqualsLiteral("ko")) { + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean); + } + } while (0); + + // last resort... (the order is same as old gfx.) + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Japanese); + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_Korean); + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN); + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK); + AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW); + + // copy into the cached array + uint32_t j; + for (j = 0; j < tempLen; j++) { + mCJKPrefLangs.AppendElement(tempPrefLangs[j]); + } + } + + // append in cached CJK langs + uint32_t i, numCJKlangs = mCJKPrefLangs.Length(); + + for (i = 0; i < numCJKlangs; i++) { + AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i])); + } + +} + +void +gfxPlatformFontList::AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang) +{ + if (aLen >= kMaxLenPrefLangList) return; + + // make sure + uint32_t i = 0; + while (i < aLen && aPrefLangs[i] != aAddLang) { + i++; + } + + if (i == aLen) { + aPrefLangs[aLen] = aAddLang; + aLen++; + } +} + +mozilla::FontFamilyType +gfxPlatformFontList::GetDefaultGeneric(eFontPrefLang aLang) +{ + // initialize lang group pref font defaults (i.e. serif/sans-serif) + if (MOZ_UNLIKELY(mDefaultGenericsLangGroup.IsEmpty())) { + mDefaultGenericsLangGroup.AppendElements(ArrayLength(gPrefLangNames)); + for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); i++) { + nsAutoCString prefDefaultFontType("font.default."); + prefDefaultFontType.Append(GetPrefLangName(eFontPrefLang(i))); + nsAdoptingCString serifOrSans = + Preferences::GetCString(prefDefaultFontType.get()); + if (serifOrSans.EqualsLiteral("sans-serif")) { + mDefaultGenericsLangGroup[i] = eFamily_sans_serif; + } else { + mDefaultGenericsLangGroup[i] = eFamily_serif; + } + } + } + + if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) { + return mDefaultGenericsLangGroup[uint32_t(aLang)]; + } + return eFamily_serif; +} + void gfxPlatformFontList::GetFontFamilyNames(nsTArray& aFontFamilyNames) { @@ -952,6 +1371,19 @@ gfxPlatformFontList::RebuildLocalFonts() } } +void +gfxPlatformFontList::ClearLangGroupPrefFonts() +{ + for (uint32_t i = eFontPrefLang_First; + i < eFontPrefLang_First + eFontPrefLang_Count; i++) { + auto& prefFontsLangGroup = mLangGroupPrefFonts[i]; + for (uint32_t j = eFamily_generic_first; + j < eFamily_generic_first + eFamily_generic_count; j++) { + prefFontsLangGroup[j] = nullptr; + } + } +} + // Support for memory reporting // this is also used by subclasses that hold additional font tables @@ -1008,21 +1440,24 @@ gfxPlatformFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, aMallocSizeOf); } + for (uint32_t i = eFontPrefLang_First; + i < eFontPrefLang_First + eFontPrefLang_Count; i++) { + auto& prefFontsLangGroup = mLangGroupPrefFonts[i]; + for (uint32_t j = eFamily_generic_first; + j < eFamily_generic_first + eFamily_generic_count; j++) { + PrefFontList* pf = prefFontsLangGroup[j]; + if (pf) { + aSizes->mFontListSize += + pf->ShallowSizeOfExcludingThis(aMallocSizeOf); + } + } + } + aSizes->mFontListSize += mCodepointsWithNoFonts.SizeOfExcludingThis(aMallocSizeOf); aSizes->mFontListSize += mFontFamiliesToLoad.ShallowSizeOfExcludingThis(aMallocSizeOf); - aSizes->mFontListSize += - mPrefFonts.ShallowSizeOfExcludingThis(aMallocSizeOf); - for (auto iter = mPrefFonts.ConstIter(); !iter.Done(); iter.Next()) { - // Again, we only care about the size of the array itself; we don't - // follow the refPtrs stored in it, because they point to entries - // already owned and accounted-for by the main font list. - aSizes->mFontListSize += - iter.Data().ShallowSizeOfExcludingThis(aMallocSizeOf); - } - aSizes->mFontListSize += mBadUnderlineFamilyNames.SizeOfExcludingThis(aMallocSizeOf); diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index 0e5fa8dd43..ea8d41633a 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -13,11 +13,15 @@ #include "gfxFontUtils.h" #include "gfxFontInfoLoader.h" #include "gfxFont.h" +#include "gfxFontConstants.h" #include "gfxPlatform.h" +#include "gfxFontFamilyList.h" #include "nsIMemoryReporter.h" #include "mozilla/Attributes.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/RangedArray.h" +#include "nsILanguageAtomService.h" class CharMapHashKey : public PLDHashEntryHdr { @@ -116,7 +120,7 @@ public: void UpdateFontList(); - void ClearPrefFonts() { mPrefFonts.Clear(); } + void ClearLangGroupPrefFonts(); virtual void GetFontFamilyList(nsTArray >& aFamilyArray); @@ -131,9 +135,6 @@ public: gfxFontEntry* FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold); - bool GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray > *array); - void SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray >& array); - // name lookup table methods void AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName); @@ -199,6 +200,43 @@ public: aLoaderState = (uint32_t) mState; } + virtual void + AddGenericFonts(mozilla::FontFamilyType aGenericType, + nsIAtom* aLanguage, + nsTArray& aFamilyList); + + nsTArray>* + GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType, + eFontPrefLang aPrefLang); + + // in some situations, need to make decisions about ambiguous characters, may need to look at multiple pref langs + void GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang); + + // convert a lang group to enum constant (i.e. "zh-TW" ==> eFontPrefLang_ChineseTW) + static eFontPrefLang GetFontPrefLangFor(const char* aLang); + + // convert a lang group atom to enum constant + static eFontPrefLang GetFontPrefLangFor(nsIAtom *aLang); + + // convert an enum constant to a lang group atom + static nsIAtom* GetLangGroupForPrefLang(eFontPrefLang aLang); + + // convert a enum constant to lang group string (i.e. eFontPrefLang_ChineseTW ==> "zh-TW") + static const char* GetPrefLangName(eFontPrefLang aLang); + + // map a Unicode range (based on char code) to a font language for Preferences + static eFontPrefLang GetFontPrefLangFor(uint8_t aUnicodeRange); + + // returns true if a pref lang is CJK + static bool IsLangCJK(eFontPrefLang aLang); + + // helper method to add a pref lang to an array, if not already in array + static void AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang); + + // default serif/sans-serif choice based on font.default.xxx prefs + mozilla::FontFamilyType + GetDefaultGeneric(eFontPrefLang aLang); + protected: class MemoryReporter final : public nsIMemoryReporter { @@ -241,6 +279,9 @@ protected: // if system fallback is used, no need to load all cmaps virtual bool UsesSystemFallback() { return false; } + void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, + eFontPrefLang aCharLang, eFontPrefLang aPageLang); + // verifies that a family contains a non-zero font count gfxFontFamily* CheckFamily(gfxFontFamily *aFamily); @@ -287,6 +328,11 @@ protected: void RebuildLocalFonts(); + void + ResolveGenericFontNames(mozilla::FontFamilyType aGenericType, + eFontPrefLang aPrefLang, + nsTArray>* aGenericFamilies); + typedef nsRefPtrHashtable FontFamilyTable; typedef nsRefPtrHashtable FontEntryTable; @@ -332,9 +378,13 @@ protected: // localized family names missed when face name loading takes a long time nsAutoPtr > mOtherNamesMissed; - // cached pref font lists - // maps list of family names ==> array of family entries, one per lang group - nsDataHashtable > > mPrefFonts; + typedef nsTArray> PrefFontList; + typedef mozilla::RangedArray, + mozilla::eFamily_generic_first, + mozilla::eFamily_generic_count> PrefFontsForLangGroup; + mozilla::RangedArray mLangGroupPrefFonts; // when system-wide font lookup fails for a character, cache it to skip future searches gfxSparseBitSet mCodepointsWithNoFonts; @@ -360,6 +410,10 @@ protected: uint32_t mFontlistInitCount; // num times InitFontList called nsTHashtable > mUserFontSetList; + + nsCOMPtr mLangService; + nsTArray mCJKPrefLangs; + nsTArray mDefaultGenericsLangGroup; }; #endif /* GFXPLATFORMFONTLIST_H_ */ diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 7ea33cb8a5..d54367769b 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -222,7 +222,6 @@ gfxTextRun::SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength, if (canBreak && !charGlyphs[i].IsClusterStart()) { // This can happen ... there is no guarantee that our linebreaking rules // align with the platform's idea of what constitutes a cluster. - NS_WARNING("Break suggested inside cluster!"); canBreak = CompressedGlyph::FLAG_BREAK_TYPE_NONE; } changed |= charGlyphs[i].SetCanBreakBefore(canBreak); @@ -515,13 +514,13 @@ HasSyntheticBold(gfxTextRun *aRun, uint32_t aStart, uint32_t aLength) return false; } -// returns true if color is non-opaque (i.e. alpha != 1.0) or completely transparent, false otherwise -// if true, color is set on output +// Returns true if color is neither opaque nor transparent (i.e. alpha is not 0 +// or 1), and false otherwise. If true, aCurrentColorOut is set on output. static bool -HasNonOpaqueColor(gfxContext *aContext, Color& aCurrentColorOut) +HasNonOpaqueNonTransparentColor(gfxContext *aContext, Color& aCurrentColorOut) { if (aContext->GetDeviceColor(aCurrentColorOut)) { - if (0.0 < aCurrentColorOut.a && aCurrentColorOut.a < 1.0) { + if (0.f < aCurrentColorOut.a && aCurrentColorOut.a < 1.f) { return true; } } @@ -532,6 +531,7 @@ HasNonOpaqueColor(gfxContext *aContext, Color& aCurrentColorOut) struct BufferAlphaColor { explicit BufferAlphaColor(gfxContext *aContext) : mContext(aContext) + , mAlpha(0.0) { } @@ -603,6 +603,25 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode, return; } + // synthetic bolding draws glyphs twice ==> colors with opacity won't draw + // correctly unless first drawn without alpha + BufferAlphaColor syntheticBoldBuffer(aContext); + Color currentColor; + bool needToRestore = false; + + if (aDrawMode == DrawMode::GLYPH_FILL && + HasNonOpaqueNonTransparentColor(aContext, currentColor) && + HasSyntheticBold(this, aStart, aLength)) { + needToRestore = true; + // measure text, use the bounding box + gfxTextRun::Metrics metrics = MeasureText(aStart, aLength, + gfxFont::LOOSE_INK_EXTENTS, + aContext, aProvider); + metrics.mBoundingBox.MoveBy(aPt); + syntheticBoldBuffer.PushSolidColor(metrics.mBoundingBox, currentColor, + GetAppUnitsPerDevUnit()); + } + // Set up parameters that will be constant across all glyph runs we need // to draw, regardless of the font used. TextRunDrawParams params; @@ -618,25 +637,6 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode, params.dt = aContext->GetDrawTarget(); params.fontSmoothingBGColor = aContext->GetFontSmoothingBackgroundColor(); - // synthetic bolding draws glyphs twice ==> colors with opacity won't draw - // correctly unless first drawn without alpha - BufferAlphaColor syntheticBoldBuffer(aContext); - Color currentColor; - bool needToRestore = false; - - if (aDrawMode == DrawMode::GLYPH_FILL && - HasNonOpaqueColor(aContext, currentColor) && - HasSyntheticBold(this, aStart, aLength)) { - needToRestore = true; - // measure text, use the bounding box - gfxTextRun::Metrics metrics = MeasureText(aStart, aLength, - gfxFont::LOOSE_INK_EXTENTS, - aContext, aProvider); - metrics.mBoundingBox.MoveBy(aPt); - syntheticBoldBuffer.PushSolidColor(metrics.mBoundingBox, currentColor, - GetAppUnitsPerDevUnit()); - } - GlyphRunIterator iter(this, aStart, aLength); gfxFloat advance = 0.0; @@ -1247,13 +1247,16 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart, // Copy glyph runs GlyphRunIterator iter(aSource, aStart, aLength); #ifdef DEBUG - gfxFont *lastFont = nullptr; + GlyphRun *prevRun = nullptr; #endif while (iter.NextRun()) { gfxFont *font = iter.GetGlyphRun()->mFont; - NS_ASSERTION(font != lastFont, "Glyphruns not coalesced?"); + NS_ASSERTION(!prevRun || prevRun->mFont != iter.GetGlyphRun()->mFont || + prevRun->mMatchType != iter.GetGlyphRun()->mMatchType || + prevRun->mOrientation != iter.GetGlyphRun()->mOrientation, + "Glyphruns not coalesced?"); #ifdef DEBUG - lastFont = font; + prevRun = iter.GetGlyphRun(); uint32_t end = iter.GetStringEnd(); #endif uint32_t start = iter.GetStringStart(); @@ -1540,7 +1543,7 @@ gfxFontGroup::gfxFontGroup(const FontFamilyList& aFontFamilyList, , mHyphenWidth(-1) , mUserFontSet(aUserFontSet) , mTextPerf(aTextPerf) - , mPageLang(gfxPlatform::GetFontPrefLangFor(aStyle->language)) + , mPageLang(gfxPlatformFontList::GetFontPrefLangFor(aStyle->language)) , mSkipDrawing(false) , mSkipUpdateUserFonts(false) { @@ -1554,138 +1557,6 @@ gfxFontGroup::~gfxFontGroup() { } -void -gfxFontGroup::FindGenericFonts(FontFamilyType aGenericType, - nsIAtom *aLanguage, - void *aClosure) -{ - nsAutoTArray resolvedGenerics; - ResolveGenericFontNames(aGenericType, aLanguage, resolvedGenerics); - uint32_t g = 0, numGenerics = resolvedGenerics.Length(); - for (g = 0; g < numGenerics; g++) { - FindPlatformFont(resolvedGenerics[g], false, aClosure); - } -} - -/* static */ void -gfxFontGroup::ResolveGenericFontNames(FontFamilyType aGenericType, - nsIAtom *aLanguage, - nsTArray& aGenericFamilies) -{ - static const char kGeneric_serif[] = "serif"; - static const char kGeneric_sans_serif[] = "sans-serif"; - static const char kGeneric_monospace[] = "monospace"; - static const char kGeneric_cursive[] = "cursive"; - static const char kGeneric_fantasy[] = "fantasy"; - - // treat -moz-fixed as monospace - if (aGenericType == eFamily_moz_fixed) { - aGenericType = eFamily_monospace; - } - - // type should be standard generic type at this point - NS_ASSERTION(aGenericType >= eFamily_serif && - aGenericType <= eFamily_fantasy, - "standard generic font family type required"); - - // create the lang string - nsIAtom *langGroupAtom = nullptr; - nsAutoCString langGroupString; - if (aLanguage) { - if (!gLangService) { - CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService); - } - if (gLangService) { - nsresult rv; - langGroupAtom = gLangService->GetLanguageGroup(aLanguage, &rv); - } - } - if (!langGroupAtom) { - langGroupAtom = nsGkAtoms::Unicode; - } - langGroupAtom->ToUTF8String(langGroupString); - - // map generic type to string - const char *generic = nullptr; - switch (aGenericType) { - case eFamily_serif: - generic = kGeneric_serif; - break; - case eFamily_sans_serif: - generic = kGeneric_sans_serif; - break; - case eFamily_monospace: - generic = kGeneric_monospace; - break; - case eFamily_cursive: - generic = kGeneric_cursive; - break; - case eFamily_fantasy: - generic = kGeneric_fantasy; - break; - default: - break; - } - - if (!generic) { - return; - } - - aGenericFamilies.Clear(); - - // load family for "font.name.generic.lang" - nsAutoCString prefFontName("font.name."); - prefFontName.Append(generic); - prefFontName.Append('.'); - prefFontName.Append(langGroupString); - gfxFontUtils::AppendPrefsFontList(prefFontName.get(), - aGenericFamilies); - - // if lang has pref fonts, also load fonts for "font.name-list.generic.lang" - if (!aGenericFamilies.IsEmpty()) { - nsAutoCString prefFontListName("font.name-list."); - prefFontListName.Append(generic); - prefFontListName.Append('.'); - prefFontListName.Append(langGroupString); - gfxFontUtils::AppendPrefsFontList(prefFontListName.get(), - aGenericFamilies); - } - -#if 0 // dump out generic mappings - printf("%s ===> ", prefFontName.get()); - for (uint32_t k = 0; k < aGenericFamilies.Length(); k++) { - if (k > 0) printf(", "); - printf("%s", NS_ConvertUTF16toUTF8(aGenericFamilies[k]).get()); - } - printf("\n"); -#endif -} - -void gfxFontGroup::EnumerateFontList(nsIAtom *aLanguage, void *aClosure) -{ - // initialize fonts in the font family list - const nsTArray& fontlist = mFamilyList.GetFontlist(); - - // lookup fonts in the fontlist - uint32_t i, numFonts = fontlist.Length(); - for (i = 0; i < numFonts; i++) { - const FontFamilyName& name = fontlist[i]; - if (name.IsNamed()) { - FindPlatformFont(name.mName, true, aClosure); - } else { - FindGenericFonts(name.mType, aLanguage, aClosure); - } - } - - // if necessary, append default generic onto the end - if (mFamilyList.GetDefaultFontType() != eFamily_none && - !mFamilyList.HasDefaultGeneric()) { - FindGenericFonts(mFamilyList.GetDefaultFontType(), - aLanguage, - aClosure); - } -} - void gfxFontGroup::BuildFontList() { @@ -1697,56 +1568,85 @@ gfxFontGroup::BuildFontList() #elif defined(MOZ_WIDGET_QT) enumerateFonts = false; #endif - if (enumerateFonts) { - EnumerateFontList(mStyle.language); + if (!enumerateFonts) { + return; } -} -void -gfxFontGroup::FindPlatformFont(const nsAString& aName, - bool aUseFontSet, - void *aClosure) -{ - bool needsBold; - gfxFontFamily *family = nullptr; - gfxFontEntry *fe = nullptr; + // initialize fonts in the font family list + nsAutoTArray fonts; + gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList(); - if (aUseFontSet) { - // First, look up in the user font set... - // If the fontSet matches the family, we must not look for a platform - // font of the same name, even if we fail to actually get a fontEntry - // here; we'll fall back to the next name in the CSS font-family list. - if (mUserFontSet) { - // Add userfonts to the fontlist whether already loaded - // or not. Loading is initiated during font matching. - family = mUserFontSet->LookupFamily(aName); - if (family) { - nsAutoTArray userfonts; - family->FindAllFontsForStyle(mStyle, userfonts, needsBold); - // add these to the fontlist - uint32_t count = userfonts.Length(); - for (uint32_t i = 0; i < count; i++) { - fe = userfonts[i]; - FamilyFace ff(family, fe, needsBold); - ff.CheckState(mSkipDrawing); - mFonts.AppendElement(ff); - } + // lookup fonts in the fontlist + for (const FontFamilyName& name : mFamilyList.GetFontlist()) { + if (name.IsNamed()) { + AddPlatformFont(name.mName, fonts); + } else { + pfl->AddGenericFonts(name.mType, mStyle.language, fonts); + if (mTextPerf) { + mTextPerf->current.genericLookups++; } } } - // Not known in the user font set ==> check system fonts - if (!family) { - gfxPlatformFontList *fontList = gfxPlatformFontList::PlatformFontList(); - family = fontList->FindFamily(aName, mStyle.language, mStyle.systemFont); - if (family) { - fe = family->FindFontForStyle(mStyle, needsBold); + // if necessary, append default generic onto the end + if (mFamilyList.GetDefaultFontType() != eFamily_none && + !mFamilyList.HasDefaultGeneric()) { + pfl->AddGenericFonts(mFamilyList.GetDefaultFontType(), + mStyle.language, fonts); + if (mTextPerf) { + mTextPerf->current.genericLookups++; } } - // add to the font group, unless it's already there - if (fe && !HasFont(fe)) { - mFonts.AppendElement(FamilyFace(family, fe, needsBold)); + // build the fontlist from the specified families + for (gfxFontFamily* fontFamily : fonts) { + AddFamilyToFontList(fontFamily); + } +} + +void +gfxFontGroup::AddPlatformFont(const nsAString& aName, + nsTArray& aFamilyList) +{ + gfxFontFamily* family = nullptr; + + // First, look up in the user font set... + // If the fontSet matches the family, we must not look for a platform + // font of the same name, even if we fail to actually get a fontEntry + // here; we'll fall back to the next name in the CSS font-family list. + if (mUserFontSet) { + // Add userfonts to the fontlist whether already loaded + // or not. Loading is initiated during font matching. + family = mUserFontSet->LookupFamily(aName); + } + + // Not known in the user font set ==> check system fonts + if (!family) { + gfxPlatformFontList* fontList = gfxPlatformFontList::PlatformFontList(); + family = fontList->FindFamily(aName, mStyle.language, mStyle.systemFont); + } + + if (family) { + aFamilyList.AppendElement(family); + } +} + +void +gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily) +{ + NS_ASSERTION(aFamily, "trying to add a null font family to fontlist"); + nsAutoTArray fontEntryList; + bool needsBold; + aFamily->FindAllFontsForStyle(mStyle, fontEntryList, needsBold); + // add these to the fontlist + for (gfxFontEntry* fe : fontEntryList) { + if (!HasFont(fe)) { + FamilyFace ff(aFamily, fe, needsBold); + if (fe->mIsUserFontContainer) { + ff.CheckState(mSkipDrawing); + } + mFonts.AppendElement(ff); + } } } @@ -2651,9 +2551,6 @@ gfxFontGroup::FindNonItalicFaceForChar(gfxFontFamily* aFamily, uint32_t aCh) } nsRefPtr font = fe->FindOrMakeFont(&mStyle, needsBold); - if (!font->Valid()) { - return nullptr; - } return font.forget(); } @@ -3008,16 +2905,40 @@ void gfxFontGroup::ComputeRanges(nsTArray& aRanges, aRanges[lastRangeIndex].end = aLength; -#if 0 - // dump out font matching info - if (mStyle.systemFont) return; - for (size_t i = 0, i_end = aRanges.Length(); i < i_end; i++) { - const gfxTextRange& r = aRanges[i]; - printf("fontmatch %zd:%zd font: %s (%d)\n", - r.start, r.end, - (r.font.get() ? - NS_ConvertUTF16toUTF8(r.font->GetName()).get() : ""), - r.matchType); +#ifndef RELEASE_BUILD + PRLogModuleInfo *log = (mStyle.systemFont ? + gfxPlatform::GetLog(eGfxLog_textrunui) : + gfxPlatform::GetLog(eGfxLog_textrun)); + + if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) { + nsAutoCString lang; + mStyle.language->ToUTF8String(lang); + nsAutoString families; + mFamilyList.ToString(families); + + // collect the font matched for each range + nsAutoCString fontMatches; + for (size_t i = 0, i_end = aRanges.Length(); i < i_end; i++) { + const gfxTextRange& r = aRanges[i]; + fontMatches.AppendPrintf(" [%u:%u] %.200s (%s)", r.start, r.end, + (r.font.get() ? + NS_ConvertUTF16toUTF8(r.font->GetName()).get() : ""), + (r.matchType == gfxTextRange::kFontGroup ? + "list" : + (r.matchType == gfxTextRange::kPrefsFallback) ? + "prefs" : "sys")); + } + MOZ_LOG(log, LogLevel::Debug,\ + ("(%s-fontmatching) fontgroup: [%s] default: %s lang: %s script: %d" + "%s\n", + (mStyle.systemFont ? "textrunui" : "textrun"), + NS_ConvertUTF16toUTF8(families).get(), + (mFamilyList.GetDefaultFontType() == eFamily_serif ? + "serif" : + (mFamilyList.GetDefaultFontType() == eFamily_sans_serif ? + "sans-serif" : "none")), + lang.get(), aRunScript, + fontMatches.get())); } #endif } @@ -3114,7 +3035,7 @@ struct PrefFontCallbackData { PrefFontCallbackData *prefFontData = static_cast(aClosure); // map pref lang to langGroup for language-sensitive lookups - nsIAtom* lang = gfxPlatform::GetLangGroupForPrefLang(aLang); + nsIAtom* lang = gfxPlatformFontList::GetLangGroupForPrefLang(aLang); gfxFontFamily *family = gfxPlatformFontList::PlatformFontList()->FindFamily(aName, lang); if (family) { @@ -3131,7 +3052,8 @@ gfxFontGroup::WhichPrefFontSupportsChar(uint32_t aCh) // get the pref font list if it hasn't been set up already uint32_t unicodeRange = FindCharUnicodeRange(aCh); - eFontPrefLang charLang = gfxPlatform::GetPlatform()->GetFontPrefLangFor(unicodeRange); + gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); + eFontPrefLang charLang = pfl->GetFontPrefLangFor(unicodeRange); // if the last pref font was the first family in the pref list, no need to recheck through a list of families if (mLastPrefFont && charLang == mLastPrefLang && @@ -3144,29 +3066,22 @@ gfxFontGroup::WhichPrefFontSupportsChar(uint32_t aCh) eFontPrefLang prefLangs[kMaxLenPrefLangList]; uint32_t i, numLangs = 0; - gfxPlatform::GetPlatform()->GetLangPrefs(prefLangs, numLangs, charLang, mPageLang); + pfl->GetLangPrefs(prefLangs, numLangs, charLang, mPageLang); for (i = 0; i < numLangs; i++) { - nsAutoTArray, 5> families; eFontPrefLang currentLang = prefLangs[i]; - - gfxPlatformFontList *fontList = gfxPlatformFontList::PlatformFontList(); - - // get the pref families for a single pref lang - if (!fontList->GetPrefFontFamilyEntries(currentLang, &families)) { - eFontPrefLang prefLangsToSearch[1] = { currentLang }; - PrefFontCallbackData prefFontData(families); - gfxPlatform::ForEachPrefFont(prefLangsToSearch, 1, PrefFontCallbackData::AddFontFamilyEntry, - &prefFontData); - fontList->SetPrefFontFamilyEntries(currentLang, families); - } + mozilla::FontFamilyType defaultGeneric = + pfl->GetDefaultGeneric(currentLang); + nsTArray>* families = + pfl->GetPrefFontsLangGroup(defaultGeneric, currentLang); + NS_ASSERTION(families, "no pref font families found"); // find the first pref font that includes the character uint32_t j, numPrefs; - numPrefs = families.Length(); + numPrefs = families->Length(); for (j = 0; j < numPrefs; j++) { // look up the appropriate face - gfxFontFamily *family = families[j]; + gfxFontFamily *family = (*families)[j]; if (!family) continue; // if a pref font is used, it's likely to be used again in the same text run. diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index f4ac1daa65..95b4cc9690 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -10,6 +10,7 @@ #include "nsString.h" #include "gfxPoint.h" #include "gfxFont.h" +#include "gfxFontConstants.h" #include "nsTArray.h" #include "gfxSkipChars.h" #include "gfxPlatform.h" @@ -832,18 +833,6 @@ public: int32_t aRunScript, gfxFont *aPrevMatchedFont, uint8_t *aMatchType); - // search through pref fonts for a character, return nullptr if no matching pref font - virtual already_AddRefed WhichPrefFontSupportsChar(uint32_t aCh); - - already_AddRefed - WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh, - int32_t aRunScript); - - template - void ComputeRanges(nsTArray& mRanges, - const T *aString, uint32_t aLength, - int32_t aRunScript, uint16_t aOrientation); - gfxUserFontSet* GetUserFontSet(); // With downloadable fonts, the composition of the font group can change as fonts are downloaded @@ -884,13 +873,19 @@ public: gfxTextRun* GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel, uint32_t aFlags, LazyReferenceContextGetter& aRefContextGetter); - // helper method for resolving generic font families - static void - ResolveGenericFontNames(mozilla::FontFamilyType aGenericType, - nsIAtom *aLanguage, - nsTArray& aGenericFamilies); - protected: + // search through pref fonts for a character, return nullptr if no matching pref font + already_AddRefed WhichPrefFontSupportsChar(uint32_t aCh); + + already_AddRefed + WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh, + int32_t aRunScript); + + template + void ComputeRanges(nsTArray& mRanges, + const T *aString, uint32_t aLength, + int32_t aRunScript, uint16_t aOrientation); + class FamilyFace { public: FamilyFace() : mFamily(nullptr), mFontEntry(nullptr), @@ -1117,18 +1112,12 @@ protected: // helper methods for looking up fonts - // iterate over the fontlist, lookup names and expand generics - void EnumerateFontList(nsIAtom *aLanguage, void *aClosure = nullptr); - - // expand a generic to a list of specific names based on prefs - void FindGenericFonts(mozilla::FontFamilyType aGenericType, - nsIAtom *aLanguage, - void *aClosure); - // lookup and add a font with a given name (i.e. *not* a generic!) - virtual void FindPlatformFont(const nsAString& aName, - bool aUseFontSet, - void *aClosure); + void AddPlatformFont(const nsAString& aName, + nsTArray& aFamilyList); + + // do style selection and add entries to list + void AddFamilyToFontList(gfxFontFamily* aFamily); static nsILanguageAtomService* gLangService; }; diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index 2f4de11b8a..ce2bb34e7e 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -140,7 +140,9 @@ public: nsRefPtr fe = aFontEntry; // remove existing entry, if already present mAvailableFonts.RemoveElement(aFontEntry); - mAvailableFonts.AppendElement(aFontEntry); + // insert at the beginning so that the last-defined font is the first + // one in the fontlist used for matching, as per CSS Fonts spec + mAvailableFonts.InsertElementAt(0, aFontEntry); if (aFontEntry->mFamilyName.IsEmpty()) { aFontEntry->mFamilyName = Name(); @@ -338,7 +340,9 @@ public: struct Key { nsCOMPtr mURI; nsCOMPtr mPrincipal; // use nullptr with data: URLs - gfxFontEntry* mFontEntry; + // The font entry MUST notify the cache when it is destroyed + // (by calling ForgetFont()). + gfxFontEntry* MOZ_NON_OWNING_REF mFontEntry; uint32_t mCRC32; uint32_t mLength; bool mPrivate; @@ -444,8 +448,8 @@ public: // The "real" font entry corresponding to this downloaded font. // The font entry MUST notify the cache when it is destroyed - // (by calling Forget()). - gfxFontEntry* mFontEntry; + // (by calling ForgetFont()). + gfxFontEntry* MOZ_NON_OWNING_REF mFontEntry; // Whether this font was loaded from a private window. bool mPrivate; @@ -647,7 +651,9 @@ protected: nsRefPtr mPlatformFontEntry; nsTArray mSrcList; uint32_t mSrcIndex; // index of loading src item - nsFontFaceLoader* mLoader; // current loader for this entry, if any + // This field is managed by the nsFontFaceLoader. In the destructor and Cancel() + // methods of nsFontFaceLoader this reference is nulled out. + nsFontFaceLoader* MOZ_NON_OWNING_REF mLoader; // current loader for this entry, if any gfxUserFontSet* mFontSet; // font-set to which the userfont entry belongs nsCOMPtr mPrincipal; }; diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index c29d0adbe5..b336c08953 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -421,6 +421,12 @@ CreateSamplingRestrictedDrawable(gfxDrawable* aDrawable, PROFILER_LABEL("gfxUtils", "CreateSamplingRestricedDrawable", js::ProfileEntry::Category::GRAPHICS); + DrawTarget* destDrawTarget = aContext->GetDrawTarget(); + if ((destDrawTarget->GetBackendType() == BackendType::DIRECT2D1_1) || + (destDrawTarget->GetBackendType() == BackendType::DIRECT2D)) { + return nullptr; + } + gfxRect clipExtents = aContext->GetClipExtents(); // Inflate by one pixel because bilinear filtering will sample at most @@ -757,13 +763,13 @@ gfxUtils::DrawPixelSnapped(gfxContext* aContext, CreateSamplingRestrictedDrawable(aDrawable, aContext, aRegion, aFormat); if (restrictedDrawable) { - drawable.swap(restrictedDrawable); - } + drawable.swap(restrictedDrawable); - // We no longer need to tile: Either we never needed to, or we already - // filled a surface with the tiled pattern; this surface can now be - // drawn without tiling. - doTile = false; + // We no longer need to tile: Either we never needed to, or we already + // filled a surface with the tiled pattern; this surface can now be + // drawn without tiling. + doTile = false; + } #endif } } diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index cfc9a1d097..de29831694 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1047,6 +1047,7 @@ LogTextPerfStats(gfxTextPerfMetrics* aTextPerf, "word-cache-space: %d word-cache-long: %d " "pref-fallbacks: %d system-fallbacks: %d " "textruns-const: %d textruns-destr: %d " + "generic-lookups: %d " "cumulative-textruns-destr: %d\n", prefix, aTextPerf->reflowCount, aCounts.numChars, (aURL ? aURL : ""), @@ -1056,6 +1057,7 @@ LogTextPerfStats(gfxTextPerfMetrics* aTextPerf, aCounts.wordCacheSpaceRules, aCounts.wordCacheLong, aCounts.fallbackPrefs, aCounts.fallbackSystem, aCounts.textrunConst, aCounts.textrunDestr, + aCounts.genericLookups, aTextPerf->cumulative.textrunDestr)); } else { MOZ_LOG(tpLog, logLevel, @@ -1066,6 +1068,7 @@ LogTextPerfStats(gfxTextPerfMetrics* aTextPerf, "word-cache-space: %d word-cache-long: %d " "pref-fallbacks: %d system-fallbacks: %d " "textruns-const: %d textruns-destr: %d " + "generic-lookups: %d " "cumulative-textruns-destr: %d\n", prefix, aTextPerf->reflowCount, aCounts.numChars, aCounts.numContentTextRuns, aCounts.numChromeTextRuns, @@ -1074,6 +1077,7 @@ LogTextPerfStats(gfxTextPerfMetrics* aTextPerf, aCounts.wordCacheSpaceRules, aCounts.wordCacheLong, aCounts.fallbackPrefs, aCounts.fallbackSystem, aCounts.textrunConst, aCounts.textrunDestr, + aCounts.genericLookups, aTextPerf->cumulative.textrunDestr)); } } diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index cfcb1e513b..cd6ccc024b 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -958,7 +958,10 @@ static bool SetColor(const nsCSSValue& aValue, const nscolor aParentColor, int32_t intValue = aValue.GetIntValue(); if (0 <= intValue) { LookAndFeel::ColorID colorID = (LookAndFeel::ColorID) intValue; - if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID, &aResult))) { + bool useStandinsForNativeColors = aPresContext && + !aPresContext->IsChrome(); + if (NS_SUCCEEDED(LookAndFeel::GetColor(colorID, + useStandinsForNativeColors, &aResult))) { result = true; } } diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 8fc417d51c..d3537d82c1 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4424,6 +4424,9 @@ pref("webgl.enable-privileged-extensions", false); pref("webgl.bypass-shader-validation", false); pref("webgl.enable-prototype-webgl2", false); pref("webgl.disable-fail-if-major-performance-caveat", false); +pref("webgl.disable-debug-renderer-info", false); +pref("webgl.renderer-string-override", ""); +pref("webgl.vendor-string-override", ""); #ifdef RELEASE_BUILD // Keep this disabled on Release and Beta for now. (see bug 1171228) diff --git a/widget/LookAndFeel.h b/widget/LookAndFeel.h index 8c328ffbeb..aa5de666a9 100644 --- a/widget/LookAndFeel.h +++ b/widget/LookAndFeel.h @@ -533,6 +533,15 @@ public: */ static nsresult GetColor(ColorID aID, nscolor* aResult); + /** + * This variant of GetColor() takes an extra Boolean parameter that allows + * the caller to ask that hard-coded color values be substituted for + * native colors (used when it is desireable to hide system colors to + * avoid system fingerprinting). + */ + static nsresult GetColor(ColorID aID, bool aUseStandinsForNativeColors, + nscolor* aResult); + /** * GetInt() and GetFloat() return a int or float value for aID. The result * might be distance, time, some flags or a int value which has particular diff --git a/widget/nsXPLookAndFeel.cpp b/widget/nsXPLookAndFeel.cpp index fce598bd5e..d4069aee52 100644 --- a/widget/nsXPLookAndFeel.cpp +++ b/widget/nsXPLookAndFeel.cpp @@ -241,6 +241,7 @@ int32_t nsXPLookAndFeel::sCachedColorBits[COLOR_CACHE_SIZE] = {0}; bool nsXPLookAndFeel::sInitialized = false; bool nsXPLookAndFeel::sUseNativeColors = true; +bool nsXPLookAndFeel::sUseStandinsForNativeColors = false; nsLookAndFeel* nsXPLookAndFeel::sInstance = nullptr; bool nsXPLookAndFeel::sShutdown = false; @@ -452,10 +453,12 @@ nsXPLookAndFeel::Init() InitColorFromPref(i); } - bool val; - if (NS_SUCCEEDED(Preferences::GetBool("ui.use_native_colors", &val))) { - sUseNativeColors = val; - } + Preferences::AddBoolVarCache(&sUseNativeColors, + "ui.use_native_colors", + sUseNativeColors); + Preferences::AddBoolVarCache(&sUseStandinsForNativeColors, + "ui.use_standins_for_native_colors", + sUseStandinsForNativeColors); if (XRE_IsContentProcess()) { mozilla::dom::ContentChild* cc = @@ -504,6 +507,153 @@ nsXPLookAndFeel::IsSpecialColor(ColorID aID, nscolor &aColor) return false; } +bool +nsXPLookAndFeel::ColorIsNotCSSAccessible(ColorID aID) +{ + bool result = false; + + switch (aID) { + case eColorID_WindowBackground: + case eColorID_WindowForeground: + case eColorID_WidgetBackground: + case eColorID_WidgetForeground: + case eColorID_WidgetSelectBackground: + case eColorID_WidgetSelectForeground: + case eColorID_Widget3DHighlight: + case eColorID_Widget3DShadow: + case eColorID_TextBackground: + case eColorID_TextForeground: + case eColorID_TextSelectBackground: + case eColorID_TextSelectForeground: + case eColorID_TextSelectBackgroundDisabled: + case eColorID_TextSelectBackgroundAttention: + case eColorID_TextHighlightBackground: + case eColorID_TextHighlightForeground: + case eColorID_IMERawInputBackground: + case eColorID_IMERawInputForeground: + case eColorID_IMERawInputUnderline: + case eColorID_IMESelectedRawTextBackground: + case eColorID_IMESelectedRawTextForeground: + case eColorID_IMESelectedRawTextUnderline: + case eColorID_IMEConvertedTextBackground: + case eColorID_IMEConvertedTextForeground: + case eColorID_IMEConvertedTextUnderline: + case eColorID_IMESelectedConvertedTextBackground: + case eColorID_IMESelectedConvertedTextForeground: + case eColorID_IMESelectedConvertedTextUnderline: + case eColorID_SpellCheckerUnderline: + result = true; + break; + default: + break; + } + + return result; +} + +nscolor +nsXPLookAndFeel::GetStandinForNativeColor(ColorID aID) +{ + nscolor result = NS_RGB(0xFF, 0xFF, 0xFF); + + // The stand-in colors are taken from the Windows 7 Aero theme + // except Mac-specific colors which are taken from Mac OS 10.7. + switch (aID) { + // CSS 2 colors: + case eColorID_activeborder: result = NS_RGB(0xB4, 0xB4, 0xB4); break; + case eColorID_activecaption: result = NS_RGB(0x99, 0xB4, 0xD1); break; + case eColorID_appworkspace: result = NS_RGB(0xAB, 0xAB, 0xAB); break; + case eColorID_background: result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID_buttonface: result = NS_RGB(0xF0, 0xF0, 0xF0); break; + case eColorID_buttonhighlight: result = NS_RGB(0xFF, 0xFF, 0xFF); break; + case eColorID_buttonshadow: result = NS_RGB(0xA0, 0xA0, 0xA0); break; + case eColorID_buttontext: result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID_captiontext: result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID_graytext: result = NS_RGB(0x6D, 0x6D, 0x6D); break; + case eColorID_highlight: result = NS_RGB(0x33, 0x99, 0xFF); break; + case eColorID_highlighttext: result = NS_RGB(0xFF, 0xFF, 0xFF); break; + case eColorID_inactiveborder: result = NS_RGB(0xF4, 0xF7, 0xFC); break; + case eColorID_inactivecaption: result = NS_RGB(0xBF, 0xCD, 0xDB); break; + case eColorID_inactivecaptiontext: + result = NS_RGB(0x43, 0x4E, 0x54); break; + case eColorID_infobackground: result = NS_RGB(0xFF, 0xFF, 0xE1); break; + case eColorID_infotext: result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID_menu: result = NS_RGB(0xF0, 0xF0, 0xF0); break; + case eColorID_menutext: result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID_scrollbar: result = NS_RGB(0xC8, 0xC8, 0xC8); break; + case eColorID_threeddarkshadow: result = NS_RGB(0x69, 0x69, 0x69); break; + case eColorID_threedface: result = NS_RGB(0xF0, 0xF0, 0xF0); break; + case eColorID_threedhighlight: result = NS_RGB(0xFF, 0xFF, 0xFF); break; + case eColorID_threedlightshadow: result = NS_RGB(0xE3, 0xE3, 0xE3); break; + case eColorID_threedshadow: result = NS_RGB(0xA0, 0xA0, 0xA0); break; + case eColorID_window: result = NS_RGB(0xFF, 0xFF, 0xFF); break; + case eColorID_windowframe: result = NS_RGB(0x64, 0x64, 0x64); break; + case eColorID_windowtext: result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID__moz_buttondefault: + result = NS_RGB(0x69, 0x69, 0x69); break; + case eColorID__moz_field: result = NS_RGB(0xFF, 0xFF, 0xFF); break; + case eColorID__moz_fieldtext: result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID__moz_dialog: result = NS_RGB(0xF0, 0xF0, 0xF0); break; + case eColorID__moz_dialogtext: result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID__moz_dragtargetzone: + result = NS_RGB(0xFF, 0xFF, 0xFF); break; + case eColorID__moz_cellhighlight: + result = NS_RGB(0xF0, 0xF0, 0xF0); break; + case eColorID__moz_cellhighlighttext: + result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID__moz_html_cellhighlight: + result = NS_RGB(0x33, 0x99, 0xFF); break; + case eColorID__moz_html_cellhighlighttext: + result = NS_RGB(0xFF, 0xFF, 0xFF); break; + case eColorID__moz_buttonhoverface: + result = NS_RGB(0xF0, 0xF0, 0xF0); break; + case eColorID__moz_buttonhovertext: + result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID__moz_menuhover: + result = NS_RGB(0x33, 0x99, 0xFF); break; + case eColorID__moz_menuhovertext: + result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID__moz_menubartext: + result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID__moz_menubarhovertext: + result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID__moz_oddtreerow: + result = NS_RGB(0xFF, 0xFF, 0xFF); break; + case eColorID__moz_mac_chrome_active: + result = NS_RGB(0xB2, 0xB2, 0xB2); break; + case eColorID__moz_mac_chrome_inactive: + result = NS_RGB(0xE1, 0xE1, 0xE1); break; + case eColorID__moz_mac_focusring: + result = NS_RGB(0x60, 0x9D, 0xD7); break; + case eColorID__moz_mac_menuselect: + result = NS_RGB(0x38, 0x75, 0xD7); break; + case eColorID__moz_mac_menushadow: + result = NS_RGB(0xA3, 0xA3, 0xA3); break; + case eColorID__moz_mac_menutextdisable: + result = NS_RGB(0x88, 0x88, 0x88); break; + case eColorID__moz_mac_menutextselect: + result = NS_RGB(0xFF, 0xFF, 0xFF); break; + case eColorID__moz_mac_disabledtoolbartext: + result = NS_RGB(0x3F, 0x3F, 0x3F); break; + case eColorID__moz_mac_secondaryhighlight: + result = NS_RGB(0xD4, 0xD4, 0xD4); break; + case eColorID__moz_win_mediatext: + result = NS_RGB(0xFF, 0xFF, 0xFF); break; + case eColorID__moz_win_communicationstext: + result = NS_RGB(0xFF, 0xFF, 0xFF); break; + case eColorID__moz_nativehyperlinktext: + result = NS_RGB(0x00, 0x66, 0xCC); break; + case eColorID__moz_comboboxtext: + result = NS_RGB(0x00, 0x00, 0x00); break; + case eColorID__moz_combobox: + result = NS_RGB(0xFF, 0xFF, 0xFF); break; + default: + break; + } + + return result; +} + // // All these routines will return NS_OK if they have a value, // in which case the nsLookAndFeel should use that value; @@ -511,7 +661,8 @@ nsXPLookAndFeel::IsSpecialColor(ColorID aID, nscolor &aColor) // platform-specific nsLookAndFeel should use its own values instead. // nsresult -nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult) +nsXPLookAndFeel::GetColorImpl(ColorID aID, bool aUseStandinsForNativeColors, + nscolor &aResult) { if (!sInitialized) Init(); @@ -597,7 +748,12 @@ nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult) } #endif // DEBUG_SYSTEM_COLOR_USE - if (IS_COLOR_CACHED(aID)) { + if (aUseStandinsForNativeColors && + (ColorIsNotCSSAccessible(aID) || !sUseStandinsForNativeColors)) { + aUseStandinsForNativeColors = false; + } + + if (!aUseStandinsForNativeColors && IS_COLOR_CACHED(aID)) { aResult = sCachedColors[aID]; return NS_OK; } @@ -631,6 +787,11 @@ nsXPLookAndFeel::GetColorImpl(ColorID aID, nscolor &aResult) return NS_OK; } + if (sUseNativeColors && aUseStandinsForNativeColors) { + aResult = GetStandinForNativeColor(aID); + return NS_OK; + } + if (sUseNativeColors && NS_SUCCEEDED(NativeGetColor(aID, aResult))) { if ((gfxPlatform::GetCMSMode() == eCMSMode_All) && !IsSpecialColor(aID, aResult)) { @@ -727,7 +888,15 @@ namespace mozilla { nsresult LookAndFeel::GetColor(ColorID aID, nscolor* aResult) { - return nsLookAndFeel::GetInstance()->GetColorImpl(aID, *aResult); + return nsLookAndFeel::GetInstance()->GetColorImpl(aID, false, *aResult); +} + +nsresult +LookAndFeel::GetColor(ColorID aID, bool aUseStandinsForNativeColors, + nscolor* aResult) +{ + return nsLookAndFeel::GetInstance()->GetColorImpl(aID, + aUseStandinsForNativeColors, *aResult); } // static diff --git a/widget/nsXPLookAndFeel.h b/widget/nsXPLookAndFeel.h index 174c410e9e..0b8a308fb3 100644 --- a/widget/nsXPLookAndFeel.h +++ b/widget/nsXPLookAndFeel.h @@ -53,7 +53,8 @@ public: // otherwise we'll return NS_ERROR_NOT_AVAILABLE, in which case, the // platform-specific nsLookAndFeel should use its own values instead. // - nsresult GetColorImpl(ColorID aID, nscolor &aResult); + nsresult GetColorImpl(ColorID aID, bool aUseStandinsForNativeColors, + nscolor &aResult); virtual nsresult GetIntImpl(IntID aID, int32_t &aResult); virtual nsresult GetFloatImpl(FloatID aID, float &aResult); @@ -94,6 +95,8 @@ protected: void InitColorFromPref(int32_t aIndex); virtual nsresult NativeGetColor(ColorID aID, nscolor &aResult) = 0; bool IsSpecialColor(ColorID aID, nscolor &aColor); + bool ColorIsNotCSSAccessible(ColorID aID); + nscolor GetStandinForNativeColor(ColorID aID); static void OnPrefChanged(const char* aPref, void* aClosure); @@ -107,6 +110,7 @@ protected: static int32_t sCachedColors[LookAndFeel::eColorID_LAST_COLOR]; static int32_t sCachedColorBits[COLOR_CACHE_SIZE]; static bool sUseNativeColors; + static bool sUseStandinsForNativeColors; static nsLookAndFeel* sInstance; static bool sShutdown;