147520b68e50572a9775a662410c5aff8300c8784Craig Stout/*
247520b68e50572a9775a662410c5aff8300c8784Craig Stout * Copyright (C) 2014 The Android Open Source Project
347520b68e50572a9775a662410c5aff8300c8784Craig Stout *
447520b68e50572a9775a662410c5aff8300c8784Craig Stout * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
547520b68e50572a9775a662410c5aff8300c8784Craig Stout * in compliance with the License. You may obtain a copy of the License at
647520b68e50572a9775a662410c5aff8300c8784Craig Stout *
747520b68e50572a9775a662410c5aff8300c8784Craig Stout * http://www.apache.org/licenses/LICENSE-2.0
847520b68e50572a9775a662410c5aff8300c8784Craig Stout *
947520b68e50572a9775a662410c5aff8300c8784Craig Stout * Unless required by applicable law or agreed to in writing, software distributed under the License
1047520b68e50572a9775a662410c5aff8300c8784Craig Stout * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
1147520b68e50572a9775a662410c5aff8300c8784Craig Stout * or implied. See the License for the specific language governing permissions and limitations under
1247520b68e50572a9775a662410c5aff8300c8784Craig Stout * the License.
1347520b68e50572a9775a662410c5aff8300c8784Craig Stout */
14ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.leanback.widget;
1547520b68e50572a9775a662410c5aff8300c8784Craig Stout
16ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
173103f63e99d47573823957f7aa34308555873221Aurimas Liutikas
184cd4cce277571385f4d1a56d5348578c38368cbeCraig Stoutimport android.graphics.Paint;
1916cb98dc4b7af5eae092a25446a0aa5133f1f5ebDake Guimport android.text.TextUtils;
20268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stoutimport android.view.LayoutInflater;
2147520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.View;
2247520b68e50572a9775a662410c5aff8300c8784Craig Stoutimport android.view.ViewGroup;
234cd4cce277571385f4d1a56d5348578c38368cbeCraig Stoutimport android.widget.TextView;
2447520b68e50572a9775a662410c5aff8300c8784Craig Stout
258619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.annotation.RestrictTo;
268619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikasimport androidx.leanback.R;
278619e0ef7062b6a714f22af993e4b440fae7ef08Aurimas Liutikas
2847520b68e50572a9775a662410c5aff8300c8784Craig Stout/**
29a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout * RowHeaderPresenter provides a default presentation for {@link HeaderItem} using a
3033c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu * {@link RowHeaderView} and optionally a TextView for description. If a subclass creates its own
3133c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu * view, the subclass must also override {@link #onCreateViewHolder(ViewGroup)},
32cb13a318e577e14461eb008071dddf762847de42Dake Gu * {@link #onSelectLevelChanged(ViewHolder)}.
3347520b68e50572a9775a662410c5aff8300c8784Craig Stout */
3447520b68e50572a9775a662410c5aff8300c8784Craig Stoutpublic class RowHeaderPresenter extends Presenter {
3547520b68e50572a9775a662410c5aff8300c8784Craig Stout
36268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout    private final int mLayoutResourceId;
374cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    private final Paint mFontMeasurePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
38ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    private boolean mNullItemVisibilityGone;
398ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    private final boolean mAnimateSelect;
40268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout
4133c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu    /**
4233c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu     * Creates default RowHeaderPresenter using a title view and a description view.
4333c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu     * @see ViewHolder#ViewHolder(View)
4433c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu     */
45268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout    public RowHeaderPresenter() {
46268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout        this(R.layout.lb_row_header);
47268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout    }
48268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout
49268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout    /**
50268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout     * @hide
51268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout     */
528e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
53268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout    public RowHeaderPresenter(int layoutResourceId) {
548ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        this(layoutResourceId, true);
558ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    }
568ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu
578ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    /**
588ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu     * @hide
598ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu     */
608e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
618ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu    public RowHeaderPresenter(int layoutResourceId, boolean animateSelect) {
62268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout        mLayoutResourceId = layoutResourceId;
638ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        mAnimateSelect = animateSelect;
64268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout    }
65268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout
66ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    /**
67ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout     * Optionally sets the view visibility to {@link View#GONE} when bound to null.
68ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout     */
69ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    public void setNullItemVisibilityGone(boolean nullItemVisibilityGone) {
70ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout        mNullItemVisibilityGone = nullItemVisibilityGone;
71ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    }
72ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout
73ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    /**
74ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout     * Returns true if the view visibility is set to {@link View#GONE} when bound to null.
75ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout     */
76ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    public boolean isNullItemVisibilityGone() {
77ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout        return mNullItemVisibilityGone;
78ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout    }
79ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout
80a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout    /**
81a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * A ViewHolder for the RowHeaderPresenter.
82a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     */
8347520b68e50572a9775a662410c5aff8300c8784Craig Stout    public static class ViewHolder extends Presenter.ViewHolder {
84cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        float mSelectLevel;
85cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        int mOriginalTextColor;
86268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout        float mUnselectAlpha;
8748cbca8d2f412611a09e4f231055f10573a1f45asusnata        RowHeaderView mTitleView;
8848cbca8d2f412611a09e4f231055f10573a1f45asusnata        TextView mDescriptionView;
89268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout
9033c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu        /**
9133c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu         * Creating a new ViewHolder that supports title and description.
9233c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu         * @param view Root of Views.
9333c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu         */
9447520b68e50572a9775a662410c5aff8300c8784Craig Stout        public ViewHolder(View view) {
9547520b68e50572a9775a662410c5aff8300c8784Craig Stout            super(view);
9648cbca8d2f412611a09e4f231055f10573a1f45asusnata            mTitleView = (RowHeaderView)view.findViewById(R.id.row_header);
9748cbca8d2f412611a09e4f231055f10573a1f45asusnata            mDescriptionView = (TextView)view.findViewById(R.id.row_header_description);
9833c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu            initColors();
9933c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu        }
10033c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu
10133c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu        /**
10233c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu         * Uses a single {@link RowHeaderView} for creating a new ViewHolder.
10333c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu         * @param view The single RowHeaderView.
10433c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu         * @hide
10533c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu         */
10633c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu        @RestrictTo(LIBRARY_GROUP)
10733c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu        public ViewHolder(RowHeaderView view) {
10833c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu            super(view);
10933c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu            mTitleView = view;
11033c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu            initColors();
11133c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu        }
11233c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu
11333c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu        void initColors() {
11433c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu            if (mTitleView != null) {
11533c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu                mOriginalTextColor = mTitleView.getCurrentTextColor();
11633c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu            }
11733c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu
11833c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu            mUnselectAlpha = view.getResources().getFraction(
11933c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu                    R.fraction.lb_browse_header_unselect_alpha, 1, 1);
12047520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
12148cbca8d2f412611a09e4f231055f10573a1f45asusnata
122cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        public final float getSelectLevel() {
123cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu            return mSelectLevel;
124cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        }
12547520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
12647520b68e50572a9775a662410c5aff8300c8784Craig Stout
12747520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
12847520b68e50572a9775a662410c5aff8300c8784Craig Stout    public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
12948cbca8d2f412611a09e4f231055f10573a1f45asusnata        View root = LayoutInflater.from(parent.getContext())
130268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout                .inflate(mLayoutResourceId, parent, false);
131268de3d2ea3de1be0725a80bbc79dd7b8b18617eCraig Stout
13248cbca8d2f412611a09e4f231055f10573a1f45asusnata        ViewHolder viewHolder = new ViewHolder(root);
1338ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (mAnimateSelect) {
1348ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            setSelectLevel(viewHolder, 0);
1358ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
136cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        return viewHolder;
13747520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
13847520b68e50572a9775a662410c5aff8300c8784Craig Stout
13947520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
14047520b68e50572a9775a662410c5aff8300c8784Craig Stout    public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
141ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout        HeaderItem headerItem = item == null ? null : ((Row) item).getHeaderItem();
14248cbca8d2f412611a09e4f231055f10573a1f45asusnata        RowHeaderPresenter.ViewHolder vh = (RowHeaderPresenter.ViewHolder)viewHolder;
14350d7840691afde416a8ce3dc8060da1adab687a1susnata        if (headerItem == null) {
14433c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu            if (vh.mTitleView != null) {
14533c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu                vh.mTitleView.setText(null);
14633c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu            }
14748cbca8d2f412611a09e4f231055f10573a1f45asusnata            if (vh.mDescriptionView != null) {
14848cbca8d2f412611a09e4f231055f10573a1f45asusnata                vh.mDescriptionView.setText(null);
14948cbca8d2f412611a09e4f231055f10573a1f45asusnata            }
15048cbca8d2f412611a09e4f231055f10573a1f45asusnata
151ac30644710e427c77b9d1f20ae385590bdac6c60Dake Gu            viewHolder.view.setContentDescription(null);
152ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout            if (mNullItemVisibilityGone) {
153ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout                viewHolder.view.setVisibility(View.GONE);
15447520b68e50572a9775a662410c5aff8300c8784Craig Stout            }
155ad9af35ec6a808136478daf7bd57d564ac517e0eCraig Stout        } else {
15633c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu            if (vh.mTitleView != null) {
15733c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu                vh.mTitleView.setText(headerItem.getName());
15833c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu            }
15948cbca8d2f412611a09e4f231055f10573a1f45asusnata            if (vh.mDescriptionView != null) {
16016cb98dc4b7af5eae092a25446a0aa5133f1f5ebDake Gu                if (TextUtils.isEmpty(headerItem.getDescription())) {
16116cb98dc4b7af5eae092a25446a0aa5133f1f5ebDake Gu                    vh.mDescriptionView.setVisibility(View.GONE);
16216cb98dc4b7af5eae092a25446a0aa5133f1f5ebDake Gu                } else {
16316cb98dc4b7af5eae092a25446a0aa5133f1f5ebDake Gu                    vh.mDescriptionView.setVisibility(View.VISIBLE);
16416cb98dc4b7af5eae092a25446a0aa5133f1f5ebDake Gu                }
16550d7840691afde416a8ce3dc8060da1adab687a1susnata                vh.mDescriptionView.setText(headerItem.getDescription());
16648cbca8d2f412611a09e4f231055f10573a1f45asusnata            }
167ac30644710e427c77b9d1f20ae385590bdac6c60Dake Gu            viewHolder.view.setContentDescription(headerItem.getContentDescription());
16850d7840691afde416a8ce3dc8060da1adab687a1susnata            viewHolder.view.setVisibility(View.VISIBLE);
16947520b68e50572a9775a662410c5aff8300c8784Craig Stout        }
17047520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
17147520b68e50572a9775a662410c5aff8300c8784Craig Stout
17247520b68e50572a9775a662410c5aff8300c8784Craig Stout    @Override
17347520b68e50572a9775a662410c5aff8300c8784Craig Stout    public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
17448cbca8d2f412611a09e4f231055f10573a1f45asusnata        RowHeaderPresenter.ViewHolder vh = (ViewHolder)viewHolder;
17533c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu        if (vh.mTitleView != null) {
17633c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu            vh.mTitleView.setText(null);
17733c8bbc49708facb096e30a98b82a743c898bdd3Dake Gu        }
17848cbca8d2f412611a09e4f231055f10573a1f45asusnata        if (vh.mDescriptionView != null) {
17948cbca8d2f412611a09e4f231055f10573a1f45asusnata            vh.mDescriptionView.setText(null);
18048cbca8d2f412611a09e4f231055f10573a1f45asusnata        }
18148cbca8d2f412611a09e4f231055f10573a1f45asusnata
1828ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (mAnimateSelect) {
1838ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu            setSelectLevel((ViewHolder) viewHolder, 0);
1848ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
18547520b68e50572a9775a662410c5aff8300c8784Craig Stout    }
186cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
187a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout    /**
188a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Sets the select level.
189a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     */
190cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    public final void setSelectLevel(ViewHolder holder, float selectLevel) {
191cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        holder.mSelectLevel = selectLevel;
192cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu        onSelectLevelChanged(holder);
193cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
194cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu
195a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout    /**
196a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     * Called when the select level changes.  The default implementation sets the alpha on the view.
197a00bada00bff4a58436a39472ab14ccb7a8f619dCraig Stout     */
198cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    protected void onSelectLevelChanged(ViewHolder holder) {
1998ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        if (mAnimateSelect) {
2003103f63e99d47573823957f7aa34308555873221Aurimas Liutikas            holder.view.setAlpha(holder.mUnselectAlpha + holder.mSelectLevel
2013103f63e99d47573823957f7aa34308555873221Aurimas Liutikas                    * (1f - holder.mUnselectAlpha));
2028ff4c54cdaf5e8164fba7eac999c1ceafc462fc8Dake Gu        }
203cf94c5fa8ae8edb7e26a623133207415ceeed187Dake Gu    }
2044cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout
2054cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    /**
2064cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout     * Returns the space (distance in pixels) below the baseline of the
2074cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout     * text view, if one exists; otherwise, returns 0.
2084cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout     */
2094cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    public int getSpaceUnderBaseline(ViewHolder holder) {
2104cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        int space = holder.view.getPaddingBottom();
2114cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        if (holder.view instanceof TextView) {
2124cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            space += (int) getFontDescent((TextView) holder.view, mFontMeasurePaint);
2134cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        }
2144cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        return space;
2154cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    }
2164cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout
217694edde99dc3782374977dab6d9aa34a16c13337Dake Gu    @SuppressWarnings("ReferenceEquality")
2184cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    protected static float getFontDescent(TextView textView, Paint fontMeasurePaint) {
2194cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        if (fontMeasurePaint.getTextSize() != textView.getTextSize()) {
2204cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            fontMeasurePaint.setTextSize(textView.getTextSize());
2214cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        }
2224cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        if (fontMeasurePaint.getTypeface() != textView.getTypeface()) {
2234cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout            fontMeasurePaint.setTypeface(textView.getTypeface());
2244cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        }
2254cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout        return fontMeasurePaint.descent();
2264cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout    }
2274cd4cce277571385f4d1a56d5348578c38368cbeCraig Stout}
228