chromium/content/public/android/java/src/org/chromium/content/browser/selection/SelectionMenuCachedResult.java

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.content.browser.selection;

import androidx.annotation.Nullable;

import org.chromium.content_public.browser.SelectionClient;
import org.chromium.content_public.browser.SelectionMenuGroup;

import java.util.Objects;
import java.util.SortedSet;

/**
 * Stores text selection state and corresponding menu items for caching purposes. The {@link
 * #canReuseResult} method handles cache checking logic. We want to check all possible scenarios for
 * {@link #mClassificationResult}:
 *
 * <ol>
 *   <li>when it's null for only one state, for e.g. current selection state but not the cached one.
 *   <li>when it's null for both states. In that case compare other params to determine equivalency.
 *   <li>when it contains result in both states. Then access the text inside it, compare it, and
 *       compare other params.
 * </ol>
 */
public class SelectionMenuCachedResult {
    private final @Nullable SelectionClient.Result mClassificationResult;
    private final boolean mIsSelectionPassword;
    private final boolean mIsSelectionReadOnly;
    private final String mSelectedText;
    private final SortedSet<SelectionMenuGroup> mLastSelectionMenuItems;

    public SelectionMenuCachedResult(
            @Nullable SelectionClient.Result classificationResult,
            boolean isSelectionPassword,
            boolean isSelectionReadOnly,
            String selectedText,
            SortedSet<SelectionMenuGroup> lastSelectionMenuItems) {
        mClassificationResult = classificationResult;
        mIsSelectionPassword = isSelectionPassword;
        mIsSelectionReadOnly = isSelectionReadOnly;
        mSelectedText = selectedText;
        mLastSelectionMenuItems = lastSelectionMenuItems;
    }

    public SortedSet<SelectionMenuGroup> getResult() {
        return mLastSelectionMenuItems;
    }

    /**
     * Handles caching logic by comparing the last selection state (params) with the current one so
     * we can utilise the cached result (menu items), if there is one.
     *
     * @param classificationResult the text classification result.
     * @param isSelectionPassword true if the selection is password.
     * @param isSelectionReadOnly true if the selection is non-editable.
     * @param selectedText the current selected text.
     * @return true if params are equivalent otherwise false.
     */
    public boolean canReuseResult(
            @Nullable SelectionClient.Result classificationResult,
            boolean isSelectionPassword,
            boolean isSelectionReadOnly,
            String selectedText) {
        if (mIsSelectionPassword != isSelectionPassword
                || mIsSelectionReadOnly != isSelectionReadOnly
                || !Objects.equals(mSelectedText, selectedText)) {
            return false;
        }
        if ((mClassificationResult == null) != (classificationResult == null)) {
            return false;
        }
        if (mClassificationResult == null) {
            return true;
        }
        if ((mClassificationResult.textClassification == null)
                != (classificationResult.textClassification == null)) {
            return false;
        }
        if (mClassificationResult.textClassification == null) {
            return true;
        } else {
            return Objects.equals(
                    mClassificationResult.textClassification.getText(),
                    classificationResult.textClassification.getText());
        }
    }
}