diff --git a/.github/fabricbot.json b/.github/fabricbot.json deleted file mode 100644 index a42cda55ad..0000000000 --- a/.github/fabricbot.json +++ /dev/null @@ -1,2834 +0,0 @@ -{ - "version": "1.0", - "tasks": [ - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssueCommentResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "operator": "not", - "operands": [ - { - "name": "isOpen", - "parameters": {} - } - ] - }, - { - "name": "isAction", - "parameters": { - "action": "created" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/no-recent-activity" - } - }, - { - "operator": "or", - "operands": [ - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-repro" - } - } - ] - }, - { - "operator": "not", - "operands": [ - { - "name": "noActivitySince", - "parameters": { - "days": 7 - } - } - ] - }, - { - "operator": "not", - "operands": [ - { - "name": "isCloseAndComment", - "parameters": {} - } - ] - }, - { - "name": "isActivitySender", - "parameters": { - "user": { - "type": "author" - } - } - }, - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "none" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issue_comment" - ], - "taskName": "[Idle Issue Management] For issues closed due to inactivity, re-open an issue if issue author posts a reply within 7 days.", - "actions": [ - { - "name": "reopenIssue", - "parameters": {} - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/no-recent-activity" - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/needs-repro" - } - }, - { - "name": "addLabel", - "parameters": { - "label": "status/needs-attention" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssueCommentResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isAction", - "parameters": { - "action": "created" - } - }, - { - "operator": "not", - "operands": [ - { - "name": "isOpen", - "parameters": {} - } - ] - }, - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "read" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 7 - } - }, - { - "operator": "not", - "operands": [ - { - "name": "isCloseAndComment", - "parameters": {} - } - ] - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issue_comment" - ], - "taskName": "[Closed Issue Management] For issues closed with no activity over 7 days, ask non-contributor to consider opening a new issue instead.", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hello lovely human, thank you for your comment on this issue. Because this issue has been closed for a period of time, please strongly consider opening a new issue linking to this issue instead to ensure better visibility of your comment. Thank you!" - } - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "frequency": [ - { - "weekDay": 0, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - }, - { - "weekDay": 1, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - }, - { - "weekDay": 2, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - }, - { - "weekDay": 3, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - }, - { - "weekDay": 4, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - }, - { - "weekDay": 5, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - }, - { - "weekDay": 6, - "hours": [ - 1, - 4, - 7, - 10, - 13, - 16, - 19, - 22 - ], - "timezoneOffset": -8 - } - ], - "searchTerms": [ - { - "name": "isClosed", - "parameters": {} - }, - { - "name": "noActivitySince", - "parameters": { - "days": 30 - } - }, - { - "name": "isUnlocked", - "parameters": {} - }, - { - "name": "isIssue", - "parameters": {} - } - ], - "taskName": "[Closed Issue Management] Lock issues closed without activity for over 30 days", - "actions": [ - { - "name": "lockIssue", - "parameters": { - "reason": "resolved" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssueCommentResponder", - "version": "1.0", - "config": { - "taskName": "[Idle Issue Management] Replace needs author feedback label with needs attention label when the author comments on an issue", - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isAction", - "parameters": { - "action": "created" - } - }, - { - "operator": "or", - "operands": [ - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-repro" - } - } - ] - }, - { - "name": "isOpen", - "parameters": {} - }, - { - "operator": "or", - "operands": [ - { - "operator": "and", - "operands": [ - { - "operator": "not", - "operands": [ - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "write" - } - } - ] - }, - { - "operator": "not", - "operands": [ - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "admin" - } - } - ] - } - ] - }, - { - "name": "isActivitySender", - "parameters": { - "user": { - "type": "author" - } - } - } - ] - } - ] - }, - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "status/needs-attention" - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/needs-repro" - } - } - ], - "eventType": "issue", - "eventNames": [ - "issue_comment" - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "taskName": "[Closed Issue Management] Remove no recent activity label from issues", - "conditions": { - "operator": "and", - "operands": [ - { - "operator": "not", - "operands": [ - { - "name": "isAction", - "parameters": { - "action": "closed" - } - } - ] - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/no-recent-activity" - } - } - ] - }, - "actions": [ - { - "name": "removeLabel", - "parameters": { - "label": "status/no-recent-activity" - } - } - ], - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssueCommentResponder", - "version": "1.0", - "config": { - "taskName": "[Idle Issue Management] Remove no recent activity label when an issue is commented on", - "conditions": { - "operator": "and", - "operands": [ - { - "name": "hasLabel", - "parameters": { - "label": "status/no-recent-activity" - } - } - ] - }, - "actions": [ - { - "name": "removeLabel", - "parameters": { - "label": "status/no-recent-activity" - } - } - ], - "eventType": "issue", - "eventNames": [ - "issue_comment" - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "taskName": "[Idle Issue Management] Close stale `status/needs-info` issues", - "frequency": [ - { - "weekDay": 1, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 2, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 3, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 4, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 5, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - } - ], - "searchTerms": [ - { - "name": "isIssue", - "parameters": {} - }, - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/no-recent-activity" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 3 - } - } - ], - "actions": [ - { - "name": "closeIssue", - "parameters": {} - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "taskName": "[Idle Issue Management] Close stale `status/needs-repro` issues", - "frequency": [ - { - "weekDay": 1, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 2, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 3, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 4, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 5, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - } - ], - "searchTerms": [ - { - "name": "isIssue", - "parameters": {} - }, - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-repro" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/no-recent-activity" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 3 - } - } - ], - "actions": [ - { - "name": "closeIssue", - "parameters": {} - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "taskName": "[Idle Issue Management] Add no recent activity label to `status/needs-info` issues", - "frequency": [ - { - "weekDay": 1, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 2, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 3, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 4, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 5, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - } - ], - "searchTerms": [ - { - "name": "isIssue", - "parameters": {} - }, - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 4 - } - }, - { - "name": "noLabel", - "parameters": { - "label": "status/no-recent-activity" - } - } - ], - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "status/no-recent-activity" - } - }, - { - "name": "addReply", - "parameters": { - "comment": "This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**. If it *is* closed, feel free to comment when you are able to provide the additional information and we will re-investigate." - } - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "taskName": "[Idle Issue Management] Add no recent activity label to `status/needs-repro` issues", - "frequency": [ - { - "weekDay": 1, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 2, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 3, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 4, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - }, - { - "weekDay": 5, - "hours": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23 - ] - } - ], - "searchTerms": [ - { - "name": "isIssue", - "parameters": {} - }, - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/needs-repro" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 4 - } - }, - { - "name": "noLabel", - "parameters": { - "label": "status/no-recent-activity" - } - } - ], - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "status/no-recent-activity" - } - }, - { - "name": "addReply", - "parameters": { - "comment": "This issue has been automatically marked as stale because it has been marked as requiring author feedback to reproduce the issue but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**. If it *is* closed, feel free to comment when you are able to provide the additional information and we will re-investigate." - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isAction", - "parameters": { - "action": "opened" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "dotnet-maestro[bot]", - "association": "CONTRIBUTOR" - } - }, - { - "name": "titleContains", - "parameters": { - "titlePattern": "Update dependencies" - } - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "[Infrastructure PRs] Add area-infrastructure label to dependency update Pull Requests", - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "area/infrastructure 🏗️" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "addedToMilestone", - "parameters": { - "milestoneName": "Backlog" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Comment: Issue moved to Backlog", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time." - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "status/needs-info" - } - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "Replace `status/needs-info` with `status/pr-needs-author-input` for PRs", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hello. I see that you've just added `status/needs-info` label to this PR.\nThat label is for Issues and not for PRs. Don't worry, I'm going to replace it with the correct one." - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/needs-info" - } - }, - { - "name": "addLabel", - "parameters": { - "label": "status/pr-needs-author-input" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "status/needs-repro" - } - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "Remove `status/needs-repro` from PRs", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hello. I see that you've just added `status/needs-repro` label to this PR.\nThat label is for Issues and not for PRs, so I removed it." - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/needs-repro" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "status/needs-info" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Add comment when `status/needs-info` is applied to issue", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hi @${issueAuthor}. We have added the `status/needs-info` label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time." - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "status/needs-repro" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Add comment when `status/needs-repro` is applied to issue", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hi @${issueAuthor}. We have added the `status/needs-repro` label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone.\n\nThis issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time." - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "or", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "control-newcontrol" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-general" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-webview" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-datetimepicker" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-picker" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-switch" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-dualscreen" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-checkbox" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-border" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-label" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-button" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-dialogalert" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-entry" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-frame" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-stepper" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-refreshview" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-image" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-activityindicator" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-radiobutton" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-slider" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-progressbar" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-pages" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-map" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Add area/controls label when any 'control-X' label is applied to the issue", - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "area/controls 🎮" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "or", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "control-newcontrol" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-general" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-webview" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-datetimepicker" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-picker" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-switch" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-dualscreen" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-checkbox" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-border" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-label" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-button" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-dialogalert" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-entry" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-frame" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-stepper" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-refreshview" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-image" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-activityindicator" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-radiobutton" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-slider" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-progressbar" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-pages" - } - }, - { - "name": "labelAdded", - "parameters": { - "label": "control-map" - } - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "Add area/controls label when any 'control-X' label is applied to the PR", - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "area/controls 🎮" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isAction", - "parameters": { - "action": "opened" - } - }, - { - "operator": "or", - "operands": [ - { - "name": "isActivitySender", - "parameters": { - "user": "alexeystrakh" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "alexkblount" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "BenBtg" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "DeanFaizal" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "jgold6" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "jmongaras" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "jonlipsky" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "JoonghyunCho" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "juanlao" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "migueBarrera" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "mikeparker104" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "myroot" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "rookiejava" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "shyunMin" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "sung-su" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "Sweekriti91" - } - } - ] - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Add 'partner' label when issue is opened by a partner", - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "partner" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "labelAdded", - "parameters": { - "label": "status/move-to-vs-feedback" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Ask user to use VS Feedback for VS issues", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Thanks for the issue report @${issueAuthor}! This issue appears to be a problem with Visual Studio, so we ask that you use the VS feedback tool to report the issue. That way it will get to the routed to the team that owns this experience in VS.\n\nIf you encounter a problem with Visual Studio, we want to know about it so that we can diagnose and fix it. By using the Report a Problem tool, you can collect detailed information about the problem, and send it to Microsoft with just a few button clicks.\n\n1. Go to the [VS feedback tool](https://docs.microsoft.com/visualstudio/ide/how-to-report-a-problem-with-visual-studio?view=vs-2022) to report the issue\n2. Close this bug, and consider adding a link to the VS Feedback issue so that others can follow its activity there.\n\nThis issue will be automatically closed in 3 days if there are no further comments." - } - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "frequency": [ - { - "weekDay": 0, - "hours": [ - 0, - 6, - 12, - 18 - ] - }, - { - "weekDay": 1, - "hours": [ - 0, - 6, - 12, - 18 - ] - }, - { - "weekDay": 2, - "hours": [ - 0, - 6, - 12, - 18 - ] - }, - { - "weekDay": 3, - "hours": [ - 0, - 6, - 12, - 18 - ] - }, - { - "weekDay": 4, - "hours": [ - 0, - 6, - 12, - 18 - ] - }, - { - "weekDay": 5, - "hours": [ - 0, - 6, - 12, - 18 - ] - }, - { - "weekDay": 6, - "hours": [ - 0, - 6, - 12, - 18 - ] - } - ], - "searchTerms": [ - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/move-to-vs-feedback" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 3 - } - } - ], - "taskName": "Close `status/move-to-vs-feedback` after 3 days of no activity", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "This issue is being closed due to inactivity. If this issue is still affecting you, please follow the steps above to use the VS Feedback Tool to report the issue." - } - }, - { - "name": "closeIssue", - "parameters": {} - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssueCommentResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "isAction", - "parameters": { - "action": "created" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/move-to-vs-feedback" - } - }, - { - "operator": "not", - "operands": [ - { - "name": "noActivitySince", - "parameters": { - "days": 3 - } - } - ] - }, - { - "operator": "not", - "operands": [ - { - "name": "isCloseAndComment", - "parameters": {} - } - ] - }, - { - "name": "isActivitySender", - "parameters": { - "user": { - "type": "author" - } - } - }, - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "none" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issue_comment" - ], - "taskName": "For issues labeled with `status/move-to-vs-feedback` mark as `status/needs-attention` if there is activity", - "actions": [ - { - "name": "removeLabel", - "parameters": { - "label": "status/move-to-vs-feedback" - } - }, - { - "name": "addLabel", - "parameters": { - "label": "status/needs-attention" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "isAction", - "parameters": { - "user": "roubachof", - "action": "opened" - } - }, - { - "operator": "or", - "operands": [ - { - "name": "isActivitySender", - "parameters": { - "user": "roubachof" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": "davidbritch" - } - } - ] - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Add 'i/great-reporter' when issue is opened by an author we know opens high quality issues", - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "i/great-reporter" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "IssuesOnlyResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "status/try-latest-version" - } - } - ] - }, - "eventType": "issue", - "eventNames": [ - "issues", - "project_card" - ], - "taskName": "Add comment when `status/try-latest-version` is applied to the issue", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hi @${issueAuthor}. We have added the `status/try-latest-version` label to this issue, which indicates that we'd like you to try and reproduce this issue on the latest available public version. This can happen because we think that this issue was fixed in a version that has just been released, or the information provided by you indicates that you might be working with an older version.\n\nIf the issue still persists, please let us know with any additional details and ideally a reproduction project provided through a GitHub repository.\n\nThis issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time." - } - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "frequency": [ - { - "weekDay": 0, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 1, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 2, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 3, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 4, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 5, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 6, - "hours": [ - 3, - 15 - ], - "timezoneOffset": 2 - } - ], - "searchTerms": [ - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/try-latest-version" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 7 - } - } - ], - "taskName": "[Idle Issue Management] Close stale `status/try-latest-version` issues", - "actions": [ - { - "name": "closeIssue", - "parameters": {} - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "read" - } - }, - { - "operator": "not", - "operands": [ - { - "name": "isActivitySender", - "parameters": { - "user": "dotnet-maestro" - } - } - ] - }, - { - "operator": "not", - "operands": [ - { - "name": "isActivitySender", - "parameters": { - "user": "dotnet-maestro-bot" - } - } - ] - }, - { - "name": "isAction", - "parameters": { - "action": "opened" - } - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "Add 'community ✨' label to community contributions", - "actions": [ - { - "name": "addLabel", - "parameters": { - "label": "community ✨" - } - }, - { - "name": "addReactionToIssue", - "parameters": { - "reaction": "heart" - } - }, - { - "name": "addReply", - "parameters": { - "comment": "Hey there @${issueAuthor}! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed." - } - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "frequency": [ - { - "weekDay": 0, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 1, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 2, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 3, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 4, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 5, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 6, - "hours": [ - 2, - 5, - 8, - 11, - 14, - 17, - 20, - 23 - ], - "timezoneOffset": 2 - } - ], - "searchTerms": [ - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "isPr", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/pr-needs-author-input" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 10 - } - }, - { - "name": "noLabel", - "parameters": { - "label": "stale" - } - } - ], - "taskName": "Stale PR reminder", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hi @${issueAuthor}.\nIt seems you haven't touched this PR for the last two weeks. To avoid accumulating old PRs, we're marking it as `stale`. As a result, it will be closed if no further activity occurs **within 4 days of this comment**." - } - }, - { - "name": "addLabel", - "parameters": { - "label": "stale" - } - } - ] - } - }, - { - "taskType": "scheduled", - "capabilityId": "ScheduledSearch", - "subCapability": "ScheduledSearch", - "version": "1.1", - "config": { - "frequency": [ - { - "weekDay": 0, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 1, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 2, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 3, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 4, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 5, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - }, - { - "weekDay": 6, - "hours": [ - 3, - 7, - 11, - 15, - 19, - 23 - ], - "timezoneOffset": 2 - } - ], - "searchTerms": [ - { - "name": "isOpen", - "parameters": {} - }, - { - "name": "isPr", - "parameters": {} - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/pr-needs-author-input" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "stale" - } - }, - { - "name": "noActivitySince", - "parameters": { - "days": 4 - } - } - ], - "taskName": "Close stale PRs", - "actions": [ - { - "name": "closeIssue", - "parameters": {} - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "hasLabel", - "parameters": { - "label": "stale" - } - }, - { - "name": "hasLabel", - "parameters": { - "label": "status/pr-needs-author-input" - } - }, - { - "name": "isActivitySender", - "parameters": { - "user": { - "type": "author" - } - } - }, - { - "operator": "not", - "operands": [ - { - "name": "activitySenderHasPermissions", - "parameters": { - "permissions": "write" - } - } - ] - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "Revitalize stale PR and reopen", - "actions": [ - { - "name": "reopenIssue", - "parameters": {} - }, - { - "name": "removeLabel", - "parameters": { - "label": "stale" - } - }, - { - "name": "removeLabel", - "parameters": { - "label": "status/pr-needs-author-input" - } - } - ] - } - }, - { - "taskType": "trigger", - "capabilityId": "IssueResponder", - "subCapability": "PullRequestResponder", - "version": "1.0", - "config": { - "conditions": { - "operator": "and", - "operands": [ - { - "name": "labelAdded", - "parameters": { - "label": "status/pr-needs-author-input" - } - } - ] - }, - "eventType": "pull_request", - "eventNames": [ - "pull_request", - "issues", - "project_card" - ], - "taskName": "Add comment when `status/pr-needs-author-input` is applied to PR", - "actions": [ - { - "name": "addReply", - "parameters": { - "comment": "Hi @${issueAuthor}. We have added the `status/pr-needs-author-input` label to this issue, which indicates that we have an open question/action for you before we can take further action. This PRwill be closed automatically in 14 days if we do not hear back from you by then - please feel free to re-open it if you come back to this PR after that time." - } - } - ] - } - } - ], - "userGroups": [] -} \ No newline at end of file diff --git a/.github/policies/resourceManagement.yml b/.github/policies/resourceManagement.yml new file mode 100644 index 0000000000..5dc7e5b351 --- /dev/null +++ b/.github/policies/resourceManagement.yml @@ -0,0 +1,562 @@ +id: +name: GitOps.PullRequestIssueManagement +description: GitOps.PullRequestIssueManagement primitive +owner: +resource: repository +disabled: false +where: +configuration: + resourceManagementConfiguration: + scheduledSearches: + - description: '[Idle Issue Management] Close stale `status/needs-info` issues' + frequencies: + - weekday: + day: Monday + time: 0:0 + - weekday: + day: Tuesday + time: 0:0 + - weekday: + day: Wednesday + time: 0:0 + - weekday: + day: Thursday + time: 0:0 + - weekday: + day: Friday + time: 0:0 + filters: + - isIssue + - isOpen + - hasLabel: + label: status/needs-info + - hasLabel: + label: status/no-recent-activity + - noActivitySince: + days: 3 + actions: + - closeIssue + - description: '[Idle Issue Management] Close stale `status/needs-repro` issues' + frequencies: + - weekday: + day: Monday + time: 0:0 + - weekday: + day: Tuesday + time: 0:0 + - weekday: + day: Wednesday + time: 0:0 + - weekday: + day: Thursday + time: 0:0 + - weekday: + day: Friday + time: 0:0 + filters: + - isIssue + - isOpen + - hasLabel: + label: status/needs-repro + - hasLabel: + label: status/no-recent-activity + - noActivitySince: + days: 3 + actions: + - closeIssue + - description: '[Idle Issue Management] Add no recent activity label to `status/needs-info` issues' + frequencies: + - weekday: + day: Monday + time: 0:0 + - weekday: + day: Tuesday + time: 0:0 + - weekday: + day: Wednesday + time: 0:0 + - weekday: + day: Thursday + time: 0:0 + - weekday: + day: Friday + time: 0:0 + filters: + - isIssue + - isOpen + - hasLabel: + label: status/needs-info + - noActivitySince: + days: 4 + - isNotLabeledWith: + label: status/no-recent-activity + actions: + - addLabel: + label: status/no-recent-activity + - addReply: + reply: This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**. If it *is* closed, feel free to comment when you are able to provide the additional information and we will re-investigate. + - description: '[Idle Issue Management] Add no recent activity label to `status/needs-repro` issues' + frequencies: + - weekday: + day: Monday + time: 0:0 + - weekday: + day: Tuesday + time: 0:0 + - weekday: + day: Wednesday + time: 0:0 + - weekday: + day: Thursday + time: 0:0 + - weekday: + day: Friday + time: 0:0 + filters: + - isIssue + - isOpen + - hasLabel: + label: status/needs-repro + - noActivitySince: + days: 4 + - isNotLabeledWith: + label: status/no-recent-activity + actions: + - addLabel: + label: status/no-recent-activity + - addReply: + reply: This issue has been automatically marked as stale because it has been marked as requiring author feedback to reproduce the issue but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**. If it *is* closed, feel free to comment when you are able to provide the additional information and we will re-investigate. + - description: Close `status/move-to-vs-feedback` after 3 days of no activity + frequencies: + - hourly: + hour: 6 + filters: + - isOpen + - hasLabel: + label: status/move-to-vs-feedback + - noActivitySince: + days: 3 + actions: + - addReply: + reply: This issue is being closed due to inactivity. If this issue is still affecting you, please follow the steps above to use the VS Feedback Tool to report the issue. + - closeIssue + - description: '[Idle Issue Management] Close stale `status/try-latest-version` issues' + frequencies: + - hourly: + hour: 12 + filters: + - isOpen + - hasLabel: + label: status/try-latest-version + - noActivitySince: + days: 7 + actions: + - closeIssue + - description: Stale PR reminder + frequencies: + - hourly: + hour: 3 + filters: + - isOpen + - isPullRequest + - hasLabel: + label: status/pr-needs-author-input + - noActivitySince: + days: 10 + - isNotLabeledWith: + label: stale + actions: + - addReply: + reply: >- + Hi @${issueAuthor}. + + It seems you haven't touched this PR for the last two weeks. To avoid accumulating old PRs, we're marking it as `stale`. As a result, it will be closed if no further activity occurs **within 4 days of this comment**. + - addLabel: + label: stale + - description: Close stale PRs + frequencies: + - hourly: + hour: 4 + filters: + - isOpen + - isPullRequest + - hasLabel: + label: status/pr-needs-author-input + - hasLabel: + label: stale + - noActivitySince: + days: 4 + actions: + - closeIssue + eventResponderTasks: + - if: + - payloadType: Issue_Comment + - isAction: + action: Created + - or: + - hasLabel: + label: status/needs-info + - hasLabel: + label: status/needs-repro + - isOpen + - or: + - and: + - not: + activitySenderHasPermission: + permission: Write + - not: + activitySenderHasPermission: + permission: Admin + - isActivitySender: + issueAuthor: True + then: + - addLabel: + label: status/needs-attention + - removeLabel: + label: status/needs-info + - removeLabel: + label: status/needs-repro + description: '[Idle Issue Management] Replace needs author feedback label with needs attention label when the author comments on an issue' + - if: + - payloadType: Issues + - not: + isAction: + action: Closed + - hasLabel: + label: status/no-recent-activity + then: + - removeLabel: + label: status/no-recent-activity + description: '[Closed Issue Management] Remove no recent activity label from issues' + - if: + - payloadType: Issue_Comment + - hasLabel: + label: status/no-recent-activity + then: + - removeLabel: + label: status/no-recent-activity + description: '[Idle Issue Management] Remove no recent activity label when an issue is commented on' + - if: + - payloadType: Pull_Request + - isAction: + action: Opened + - isActivitySender: + user: dotnet-maestro[bot] + issueAuthor: False + - titleContains: + pattern: Update dependencies + isRegex: False + then: + - addLabel: + label: "area/infrastructure \U0001F3D7️" + description: '[Infrastructure PRs] Add area-infrastructure label to dependency update Pull Requests' + - if: + - payloadType: Pull_Request + - labelAdded: + label: status/needs-info + then: + - addReply: + reply: >- + Hello. I see that you've just added `status/needs-info` label to this PR. + + That label is for Issues and not for PRs. Don't worry, I'm going to replace it with the correct one. + - removeLabel: + label: status/needs-info + - addLabel: + label: status/pr-needs-author-input + description: Replace `status/needs-info` with `status/pr-needs-author-input` for PRs + - if: + - payloadType: Pull_Request + - labelAdded: + label: status/needs-repro + then: + - addReply: + reply: >- + Hello. I see that you've just added `status/needs-repro` label to this PR. + + That label is for Issues and not for PRs, so I removed it. + - removeLabel: + label: status/needs-repro + description: Remove `status/needs-repro` from PRs + - if: + - payloadType: Issues + - labelAdded: + label: status/needs-info + then: + - addReply: + reply: Hi @${issueAuthor}. We have added the `status/needs-info` label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time. + description: Add comment when `status/needs-info` is applied to issue + - if: + - payloadType: Issues + - labelAdded: + label: status/needs-repro + then: + - addReply: + reply: >- + Hi @${issueAuthor}. We have added the `status/needs-repro` label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone. + + + This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time. + description: Add comment when `status/needs-repro` is applied to issue + - if: + - payloadType: Issues + - or: + - labelAdded: + label: control-newcontrol + - labelAdded: + label: control-general + - labelAdded: + label: control-webview + - labelAdded: + label: control-datetimepicker + - labelAdded: + label: control-picker + - labelAdded: + label: control-switch + - labelAdded: + label: control-dualscreen + - labelAdded: + label: control-checkbox + - labelAdded: + label: control-border + - labelAdded: + label: control-label + - labelAdded: + label: control-button + - labelAdded: + label: control-dialogalert + - labelAdded: + label: control-entry + - labelAdded: + label: control-frame + - labelAdded: + label: control-stepper + - labelAdded: + label: control-refreshview + - labelAdded: + label: control-image + - labelAdded: + label: control-activityindicator + - labelAdded: + label: control-radiobutton + - labelAdded: + label: control-slider + - labelAdded: + label: control-progressbar + - labelAdded: + label: control-pages + - labelAdded: + label: control-map + then: + - addLabel: + label: "area/controls \U0001F3AE" + description: Add area/controls label when any 'control-X' label is applied to the issue + - if: + - payloadType: Pull_Request + - or: + - labelAdded: + label: control-newcontrol + - labelAdded: + label: control-general + - labelAdded: + label: control-webview + - labelAdded: + label: control-datetimepicker + - labelAdded: + label: control-picker + - labelAdded: + label: control-switch + - labelAdded: + label: control-dualscreen + - labelAdded: + label: control-checkbox + - labelAdded: + label: control-border + - labelAdded: + label: control-label + - labelAdded: + label: control-button + - labelAdded: + label: control-dialogalert + - labelAdded: + label: control-entry + - labelAdded: + label: control-frame + - labelAdded: + label: control-stepper + - labelAdded: + label: control-refreshview + - labelAdded: + label: control-image + - labelAdded: + label: control-activityindicator + - labelAdded: + label: control-radiobutton + - labelAdded: + label: control-slider + - labelAdded: + label: control-progressbar + - labelAdded: + label: control-pages + - labelAdded: + label: control-map + then: + - addLabel: + label: "area/controls \U0001F3AE" + description: Add area/controls label when any 'control-X' label is applied to the PR + - if: + - payloadType: Issues + - isAction: + action: Opened + - or: + - isActivitySender: + user: alexeystrakh + issueAuthor: False + - isActivitySender: + user: alexkblount + issueAuthor: False + - isActivitySender: + user: BenBtg + issueAuthor: False + - isActivitySender: + user: DeanFaizal + issueAuthor: False + - isActivitySender: + user: jgold6 + issueAuthor: False + - isActivitySender: + user: jmongaras + issueAuthor: False + - isActivitySender: + user: jonlipsky + issueAuthor: False + - isActivitySender: + user: JoonghyunCho + issueAuthor: False + - isActivitySender: + user: juanlao + issueAuthor: False + - isActivitySender: + user: migueBarrera + issueAuthor: False + - isActivitySender: + user: mikeparker104 + issueAuthor: False + - isActivitySender: + user: myroot + issueAuthor: False + - isActivitySender: + user: rookiejava + issueAuthor: False + - isActivitySender: + user: shyunMin + issueAuthor: False + - isActivitySender: + user: sung-su + issueAuthor: False + - isActivitySender: + user: Sweekriti91 + issueAuthor: False + then: + - addLabel: + label: partner + description: Add 'partner' label when issue is opened by a partner + - if: + - payloadType: Issues + - isOpen + - labelAdded: + label: status/move-to-vs-feedback + then: + - addReply: + reply: >- + Thanks for the issue report @${issueAuthor}! This issue appears to be a problem with Visual Studio, so we ask that you use the VS feedback tool to report the issue. That way it will get to the routed to the team that owns this experience in VS. + + + If you encounter a problem with Visual Studio, we want to know about it so that we can diagnose and fix it. By using the Report a Problem tool, you can collect detailed information about the problem, and send it to Microsoft with just a few button clicks. + + + 1. Go to the [VS feedback tool](https://docs.microsoft.com/visualstudio/ide/how-to-report-a-problem-with-visual-studio?view=vs-2022) to report the issue + + 2. Close this bug, and consider adding a link to the VS Feedback issue so that others can follow its activity there. + + + This issue will be automatically closed in 3 days if there are no further comments. + description: Ask user to use VS Feedback for VS issues + - if: + - payloadType: Issues + - isAction: + action: Opened + - or: + - isActivitySender: + user: roubachof + issueAuthor: False + - isActivitySender: + user: davidbritch + issueAuthor: False + then: + - addLabel: + label: i/great-reporter + description: Add 'i/great-reporter' when issue is opened by an author we know opens high quality issues + - if: + - payloadType: Issues + - labelAdded: + label: status/try-latest-version + then: + - addReply: + reply: >- + Hi @${issueAuthor}. We have added the `status/try-latest-version` label to this issue, which indicates that we'd like you to try and reproduce this issue on the latest available public version. This can happen because we think that this issue was fixed in a version that has just been released, or the information provided by you indicates that you might be working with an older version. + + + If the issue still persists, please let us know with any additional details and ideally a reproduction project provided through a GitHub repository. + + + This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time. + description: Add comment when `status/try-latest-version` is applied to the issue + - if: + - payloadType: Pull_Request + - activitySenderHasPermission: + permission: Read + - not: + isActivitySender: + user: dotnet-maestro + issueAuthor: False + - not: + isActivitySender: + user: dotnet-maestro-bot + issueAuthor: False + - isAction: + action: Opened + then: + - addLabel: + label: community ✨ + - addReply: + reply: Hey there @${issueAuthor}! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. + description: Add 'community ✨' label to community contributions + - if: + - payloadType: Pull_Request + - hasLabel: + label: stale + - hasLabel: + label: status/pr-needs-author-input + - isActivitySender: + issueAuthor: True + - not: + activitySenderHasPermission: + permission: Write + then: + - reopenIssue + - removeLabel: + label: stale + - removeLabel: + label: status/pr-needs-author-input + description: Revitalize stale PR and reopen + - if: + - payloadType: Pull_Request + - labelAdded: + label: status/pr-needs-author-input + then: + - addReply: + reply: Hi @${issueAuthor}. We have added the `status/pr-needs-author-input` label to this issue, which indicates that we have an open question/action for you before we can take further action. This PRwill be closed automatically in 14 days if we do not hear back from you by then - please feel free to re-open it if you come back to this PR after that time. + description: Add comment when `status/pr-needs-author-input` is applied to PR +onFailure: +onSuccess: diff --git a/binding/SkiaSharp/SKRunBuffer.cs b/binding/SkiaSharp/SKRunBuffer.cs index 8f4916104e..65831136ef 100644 --- a/binding/SkiaSharp/SKRunBuffer.cs +++ b/binding/SkiaSharp/SKRunBuffer.cs @@ -1,10 +1,11 @@ #nullable disable using System; -using System.ComponentModel; namespace SkiaSharp { + // Base + public unsafe class SKRunBuffer { internal readonly SKRunBufferInternal internalBuffer; @@ -17,103 +18,142 @@ internal SKRunBuffer (SKRunBufferInternal buffer, int size) public int Size { get; } - public Span GetGlyphSpan () => - new Span (internalBuffer.glyphs, internalBuffer.glyphs == null ? 0 : Size); + public Span Glyphs => new (internalBuffer.glyphs, Size); + + public void SetGlyphs (ReadOnlySpan glyphs) => glyphs.CopyTo (Glyphs); - public void SetGlyphs (ReadOnlySpan glyphs) => - glyphs.CopyTo (GetGlyphSpan ()); + [Obsolete ("Use Glyphs instead.")] + public Span GetGlyphSpan () => Glyphs; } public sealed unsafe class SKHorizontalRunBuffer : SKRunBuffer { - internal SKHorizontalRunBuffer (SKRunBufferInternal buffer, int count) - : base (buffer, count) + internal SKHorizontalRunBuffer (SKRunBufferInternal buffer, int size) + : base (buffer, size) { } - public Span GetPositionSpan () => - new Span (internalBuffer.pos, internalBuffer.pos == null ? 0 : Size); + public Span Positions => new (internalBuffer.pos, Size); - public void SetPositions (ReadOnlySpan positions) => - positions.CopyTo (GetPositionSpan ()); + public void SetPositions (ReadOnlySpan positions) => positions.CopyTo (Positions); + + [Obsolete ("Use Positions instead.")] + public Span GetPositionSpan () => Positions; } public sealed unsafe class SKPositionedRunBuffer : SKRunBuffer { - internal SKPositionedRunBuffer (SKRunBufferInternal buffer, int count) - : base (buffer, count) + internal SKPositionedRunBuffer (SKRunBufferInternal buffer, int size) + : base (buffer, size) { } - public Span GetPositionSpan () => - new Span (internalBuffer.pos, internalBuffer.pos == null ? 0 : Size); + public Span Positions => new (internalBuffer.pos, Size); + + public void SetPositions (ReadOnlySpan positions) => positions.CopyTo (Positions); - public void SetPositions (ReadOnlySpan positions) => - positions.CopyTo (GetPositionSpan ()); + [Obsolete ("Use Positions instead.")] + public Span GetPositionSpan () => Positions; } public sealed unsafe class SKRotationScaleRunBuffer : SKRunBuffer { - internal SKRotationScaleRunBuffer (SKRunBufferInternal buffer, int count) - : base (buffer, count) + internal SKRotationScaleRunBuffer (SKRunBufferInternal buffer, int size) + : base (buffer, size) { } - public Span GetRotationScaleSpan () => - new Span (internalBuffer.pos, Size); + public Span Positions => new (internalBuffer.pos, Size); - public void SetRotationScale (ReadOnlySpan positions) => - positions.CopyTo (GetRotationScaleSpan ()); + public void SetPositions (ReadOnlySpan positions) => positions.CopyTo (Positions); + + [Obsolete ("Use Positions instead.")] + public Span GetRotationScaleSpan () => Positions; + + [Obsolete ("Use SetPositions instead.")] + public void SetRotationScale (ReadOnlySpan positions) => SetPositions (positions); } + // Text + public unsafe class SKTextRunBuffer : SKRunBuffer { - internal SKTextRunBuffer (SKRunBufferInternal buffer, int count, int textSize) - : base (buffer, count) + internal SKTextRunBuffer (SKRunBufferInternal buffer, int size, int textSize) + : base (buffer, size) { TextSize = textSize; } public int TextSize { get; } - public Span GetTextSpan () => - new Span (internalBuffer.utf8text, internalBuffer.utf8text == null ? 0 : TextSize); + public Span Text => new (internalBuffer.utf8text, TextSize); - public Span GetClusterSpan () => - new Span (internalBuffer.clusters, internalBuffer.clusters == null ? 0 : Size); + public Span Clusters => new (internalBuffer.clusters, Size); - public void SetText (ReadOnlySpan text) => - text.CopyTo (GetTextSpan ()); + public void SetText (ReadOnlySpan text) => text.CopyTo (Text); - public void SetClusters (ReadOnlySpan clusters) => - clusters.CopyTo (GetClusterSpan ()); + public void SetClusters (ReadOnlySpan clusters) => clusters.CopyTo (Clusters); } public sealed unsafe class SKHorizontalTextRunBuffer : SKTextRunBuffer { - internal SKHorizontalTextRunBuffer (SKRunBufferInternal buffer, int count, int textSize) - : base (buffer, count, textSize) + internal SKHorizontalTextRunBuffer (SKRunBufferInternal buffer, int size, int textSize) + : base (buffer, size, textSize) { } - public Span GetPositionSpan () => - new Span (internalBuffer.pos, internalBuffer.pos == null ? 0 : Size); + public Span Positions => new (internalBuffer.pos, Size); - public void SetPositions (ReadOnlySpan positions) => - positions.CopyTo (GetPositionSpan ()); + public void SetPositions (ReadOnlySpan positions) => positions.CopyTo (Positions); } public sealed unsafe class SKPositionedTextRunBuffer : SKTextRunBuffer { - internal SKPositionedTextRunBuffer (SKRunBufferInternal buffer, int count, int textSize) - : base (buffer, count, textSize) + internal SKPositionedTextRunBuffer (SKRunBufferInternal buffer, int size, int textSize) + : base (buffer, size, textSize) { } - public Span GetPositionSpan () => - new Span (internalBuffer.pos, internalBuffer.pos == null ? 0 : Size); + public Span Positions => new (internalBuffer.pos, Size); + + public void SetPositions (ReadOnlySpan positions) => positions.CopyTo (Positions); + } + + public sealed unsafe class SKRotationScaleTextRunBuffer : SKTextRunBuffer + { + internal SKRotationScaleTextRunBuffer (SKRunBufferInternal buffer, int size, int textSize) + : base (buffer, size, textSize) + { + } + + public Span Positions => new (internalBuffer.pos, Size); + + public void SetPositions (ReadOnlySpan positions) => positions.CopyTo (Positions); + } + + // Raw / Struct + + public unsafe readonly struct SKRawRunBuffer + { + internal readonly SKRunBufferInternal buffer; + private readonly int size; + private readonly int posSize; + private readonly int textSize; + + internal SKRawRunBuffer (SKRunBufferInternal buffer, int size, int posSize, int textSize) + { + this.buffer = buffer; + this.size = size; + this.posSize = posSize; + this.textSize = textSize; + } + + public Span Glyphs => new (buffer.glyphs, size); + + public Span Positions => new (buffer.pos, posSize); + + public Span Text => new (buffer.utf8text, textSize); - public void SetPositions (ReadOnlySpan positions) => - positions.CopyTo (GetPositionSpan ()); + public Span Clusters => new (buffer.clusters, size); } } diff --git a/binding/SkiaSharp/SKTextBlob.cs b/binding/SkiaSharp/SKTextBlob.cs index 704b3e95b8..10193d25a0 100644 --- a/binding/SkiaSharp/SKTextBlob.cs +++ b/binding/SkiaSharp/SKTextBlob.cs @@ -1,7 +1,4 @@ -#nullable disable - -using System; -using System.ComponentModel; +using System; namespace SkiaSharp { @@ -31,27 +28,27 @@ public SKRect Bounds { // Create - public static SKTextBlob Create (string text, SKFont font, SKPoint origin = default) => + public static SKTextBlob? Create (string text, SKFont font, SKPoint origin = default) => Create (text.AsSpan (), font, origin); - public static SKTextBlob Create (ReadOnlySpan text, SKFont font, SKPoint origin = default) + public static SKTextBlob? Create (ReadOnlySpan text, SKFont font, SKPoint origin = default) { fixed (void* t = text) { return Create (t, text.Length * 2, SKTextEncoding.Utf16, font, origin); } } - public static SKTextBlob Create (IntPtr text, int length, SKTextEncoding encoding, SKFont font, SKPoint origin = default) => + public static SKTextBlob? Create (IntPtr text, int length, SKTextEncoding encoding, SKFont font, SKPoint origin = default) => Create (text.AsReadOnlySpan (length), encoding, font, origin); - public static SKTextBlob Create (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, SKPoint origin = default) + public static SKTextBlob? Create (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, SKPoint origin = default) { fixed (void* t = text) { return Create (t, text.Length, encoding, font, origin); } } - internal static SKTextBlob Create (void* text, int length, SKTextEncoding encoding, SKFont font, SKPoint origin) + internal static SKTextBlob? Create (void* text, int length, SKTextEncoding encoding, SKFont font, SKPoint origin) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -61,35 +58,35 @@ internal static SKTextBlob Create (void* text, int length, SKTextEncoding encodi return null; using var builder = new SKTextBlobBuilder (); - var buffer = builder.AllocatePositionedRun (font, count); - font.GetGlyphs (text, length, encoding, buffer.GetGlyphSpan ()); - font.GetGlyphPositions (buffer.GetGlyphSpan (), buffer.GetPositionSpan (), origin); + var buffer = builder.AllocateRawPositionedRun (font, count); + font.GetGlyphs (text, length, encoding, buffer.Glyphs); + font.GetGlyphPositions (buffer.Glyphs, buffer.Positions, origin); return builder.Build (); } // CreateHorizontal - public static SKTextBlob CreateHorizontal (string text, SKFont font, ReadOnlySpan positions, float y) => + public static SKTextBlob? CreateHorizontal (string text, SKFont font, ReadOnlySpan positions, float y) => CreateHorizontal (text.AsSpan (), font, positions, y); - public static SKTextBlob CreateHorizontal (ReadOnlySpan text, SKFont font, ReadOnlySpan positions, float y) + public static SKTextBlob? CreateHorizontal (ReadOnlySpan text, SKFont font, ReadOnlySpan positions, float y) { fixed (void* t = text) { return CreateHorizontal (t, text.Length * 2, SKTextEncoding.Utf16, font, positions, y); } } - public static SKTextBlob CreateHorizontal (IntPtr text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions, float y) => + public static SKTextBlob? CreateHorizontal (IntPtr text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions, float y) => CreateHorizontal (text.AsReadOnlySpan (length), encoding, font, positions, y); - public static SKTextBlob CreateHorizontal (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions, float y) + public static SKTextBlob? CreateHorizontal (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions, float y) { fixed (void* t = text) { return CreateHorizontal (t, text.Length, encoding, font, positions, y); } } - internal static SKTextBlob CreateHorizontal (void* text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions, float y) + internal static SKTextBlob? CreateHorizontal (void* text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions, float y) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -99,35 +96,35 @@ internal static SKTextBlob CreateHorizontal (void* text, int length, SKTextEncod return null; using var builder = new SKTextBlobBuilder (); - var buffer = builder.AllocateHorizontalRun (font, count, y); - font.GetGlyphs (text, length, encoding, buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetPositionSpan ()); + var buffer = builder.AllocateRawHorizontalRun (font, count, y); + font.GetGlyphs (text, length, encoding, buffer.Glyphs); + positions.CopyTo (buffer.Positions); return builder.Build (); } // CreatePositioned - public static SKTextBlob CreatePositioned (string text, SKFont font, ReadOnlySpan positions) => + public static SKTextBlob? CreatePositioned (string text, SKFont font, ReadOnlySpan positions) => CreatePositioned (text.AsSpan (), font, positions); - public static SKTextBlob CreatePositioned (ReadOnlySpan text, SKFont font, ReadOnlySpan positions) + public static SKTextBlob? CreatePositioned (ReadOnlySpan text, SKFont font, ReadOnlySpan positions) { fixed (void* t = text) { return CreatePositioned (t, text.Length * 2, SKTextEncoding.Utf16, font, positions); } } - public static SKTextBlob CreatePositioned (IntPtr text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) => + public static SKTextBlob? CreatePositioned (IntPtr text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) => CreatePositioned (text.AsReadOnlySpan (length), encoding, font, positions); - public static SKTextBlob CreatePositioned (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) + public static SKTextBlob? CreatePositioned (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) { fixed (void* t = text) { return CreatePositioned (t, text.Length, encoding, font, positions); } } - internal static SKTextBlob CreatePositioned (void* text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) + internal static SKTextBlob? CreatePositioned (void* text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -137,35 +134,35 @@ internal static SKTextBlob CreatePositioned (void* text, int length, SKTextEncod return null; using var builder = new SKTextBlobBuilder (); - var buffer = builder.AllocatePositionedRun (font, count); - font.GetGlyphs (text, length, encoding, buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetPositionSpan ()); + var buffer = builder.AllocateRawPositionedRun (font, count); + font.GetGlyphs (text, length, encoding, buffer.Glyphs); + positions.CopyTo (buffer.Positions); return builder.Build (); } // CreateRotationScale - public static SKTextBlob CreateRotationScale (string text, SKFont font, ReadOnlySpan positions) => + public static SKTextBlob? CreateRotationScale (string text, SKFont font, ReadOnlySpan positions) => CreateRotationScale (text.AsSpan (), font, positions); - public static SKTextBlob CreateRotationScale (ReadOnlySpan text, SKFont font, ReadOnlySpan positions) + public static SKTextBlob? CreateRotationScale (ReadOnlySpan text, SKFont font, ReadOnlySpan positions) { fixed (void* t = text) { return CreateRotationScale (t, text.Length * 2, SKTextEncoding.Utf16, font, positions); } } - public static SKTextBlob CreateRotationScale (IntPtr text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) => + public static SKTextBlob? CreateRotationScale (IntPtr text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) => CreateRotationScale (text.AsReadOnlySpan (length), encoding, font, positions); - public static SKTextBlob CreateRotationScale (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) + public static SKTextBlob? CreateRotationScale (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) { fixed (void* t = text) { return CreateRotationScale (t, text.Length, encoding, font, positions); } } - internal static SKTextBlob CreateRotationScale (void* text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) + internal static SKTextBlob? CreateRotationScale (void* text, int length, SKTextEncoding encoding, SKFont font, ReadOnlySpan positions) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -176,34 +173,34 @@ internal static SKTextBlob CreateRotationScale (void* text, int length, SKTextEn using var builder = new SKTextBlobBuilder (); var buffer = builder.AllocateRotationScaleRun (font, count); - font.GetGlyphs (text, length, encoding, buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetRotationScaleSpan ()); + font.GetGlyphs (text, length, encoding, buffer.Glyphs); + positions.CopyTo (buffer.Positions); return builder.Build (); } // CreatePathPositioned - public static SKTextBlob CreatePathPositioned (string text, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) => + public static SKTextBlob? CreatePathPositioned (string text, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) => CreatePathPositioned (text.AsSpan (), font, path, textAlign, origin); - public static SKTextBlob CreatePathPositioned (ReadOnlySpan text, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) + public static SKTextBlob? CreatePathPositioned (ReadOnlySpan text, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) { fixed (void* t = text) { return CreatePathPositioned (t, text.Length * 2, SKTextEncoding.Utf16, font, path, textAlign, origin); } } - public static SKTextBlob CreatePathPositioned (IntPtr text, int length, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) => + public static SKTextBlob? CreatePathPositioned (IntPtr text, int length, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) => CreatePathPositioned (text.AsReadOnlySpan (length), encoding, font, path, textAlign, origin); - public static SKTextBlob CreatePathPositioned (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) + public static SKTextBlob? CreatePathPositioned (ReadOnlySpan text, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) { fixed (void* t = text) { return CreatePathPositioned (t, text.Length, encoding, font, path, textAlign, origin); } } - internal static SKTextBlob CreatePathPositioned (void* text, int length, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) + internal static SKTextBlob? CreatePathPositioned (void* text, int length, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = default) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -228,7 +225,7 @@ internal static SKTextBlob CreatePathPositioned (void* text, int length, SKTextE // GetIntercepts - public float[] GetIntercepts (float upperBounds, float lowerBounds, SKPaint paint = null) + public float[] GetIntercepts (float upperBounds, float lowerBounds, SKPaint? paint = null) { var n = CountIntercepts (upperBounds, lowerBounds, paint); var intervals = new float[n]; @@ -236,7 +233,7 @@ public float[] GetIntercepts (float upperBounds, float lowerBounds, SKPaint pain return intervals; } - public void GetIntercepts (float upperBounds, float lowerBounds, Span intervals, SKPaint paint = null) + public void GetIntercepts (float upperBounds, float lowerBounds, Span intervals, SKPaint? paint = null) { var bounds = stackalloc float[2]; bounds[0] = upperBounds; @@ -248,7 +245,7 @@ public void GetIntercepts (float upperBounds, float lowerBounds, Span int // CountIntercepts - public int CountIntercepts (float upperBounds, float lowerBounds, SKPaint paint = null) + public int CountIntercepts (float upperBounds, float lowerBounds, SKPaint? paint = null) { var bounds = stackalloc float[2]; bounds[0] = upperBounds; @@ -258,7 +255,7 @@ public int CountIntercepts (float upperBounds, float lowerBounds, SKPaint paint // - internal static SKTextBlob GetObject (IntPtr handle) => + internal static SKTextBlob? GetObject (IntPtr handle) => handle == IntPtr.Zero ? null : new SKTextBlob (handle, true); } @@ -282,7 +279,7 @@ protected override void DisposeNative () => // Build - public SKTextBlob Build () + public SKTextBlob? Build () { var blob = SKTextBlob.GetObject (SkiaApi.sk_textblob_builder_make (Handle)); GC.KeepAlive (this); @@ -293,48 +290,36 @@ public SKTextBlob Build () public void AddRun (ReadOnlySpan glyphs, SKFont font, SKPoint origin = default) { - if (font == null) - throw new ArgumentNullException (nameof (font)); - - var buffer = AllocatePositionedRun (font, glyphs.Length); - glyphs.CopyTo (buffer.GetGlyphSpan ()); - font.GetGlyphPositions (buffer.GetGlyphSpan (), buffer.GetPositionSpan (), origin); + var buffer = AllocateRawPositionedRun (font, glyphs.Length); + glyphs.CopyTo (buffer.Glyphs); + font.GetGlyphPositions (buffer.Glyphs, buffer.Positions, origin); } // AddHorizontalRun public void AddHorizontalRun (ReadOnlySpan glyphs, SKFont font, ReadOnlySpan positions, float y) { - if (font == null) - throw new ArgumentNullException (nameof (font)); - - var buffer = AllocateHorizontalRun (font, glyphs.Length, y); - glyphs.CopyTo (buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetPositionSpan ()); + var buffer = AllocateRawHorizontalRun (font, glyphs.Length, y); + glyphs.CopyTo (buffer.Glyphs); + positions.CopyTo (buffer.Positions); } // AddPositionedRun public void AddPositionedRun (ReadOnlySpan glyphs, SKFont font, ReadOnlySpan positions) { - if (font == null) - throw new ArgumentNullException (nameof (font)); - - var buffer = AllocatePositionedRun (font, glyphs.Length); - glyphs.CopyTo (buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetPositionSpan ()); + var buffer = AllocateRawPositionedRun (font, glyphs.Length); + glyphs.CopyTo (buffer.Glyphs); + positions.CopyTo (buffer.Positions); } // AddRotationScaleRun public void AddRotationScaleRun (ReadOnlySpan glyphs, SKFont font, ReadOnlySpan positions) { - if (font == null) - throw new ArgumentNullException (nameof (font)); - - var buffer = AllocateRotationScaleRun (font, glyphs.Length); - glyphs.CopyTo (buffer.GetGlyphSpan ()); - positions.CopyTo (buffer.GetRotationScaleSpan ()); + var buffer = AllocateRawRotationScaleRun (font, glyphs.Length); + glyphs.CopyTo (buffer.Glyphs); + positions.CopyTo (buffer.Positions); } // AddPathPositionedRun @@ -390,9 +375,17 @@ public void AddPathPositionedRun (ReadOnlySpan glyphs, SKFont font, Read AddRotationScaleRun (glyphSubset, font, positions); } - // AllocateRun + // Allocate* + + // Allocate*Run public SKRunBuffer AllocateRun (SKFont font, int count, float x, float y, SKRect? bounds = null) + { + var buffer = AllocateRawRun (font, count, x, y, bounds); + return new SKRunBuffer (buffer.buffer, count); + } + + public SKRawRunBuffer AllocateRawRun (SKFont font, int count, float x, float y, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -403,10 +396,16 @@ public SKRunBuffer AllocateRun (SKFont font, int count, float x, float y, SKRect else SkiaApi.sk_textblob_builder_alloc_run (Handle, font.Handle, count, x, y, null, &runbuffer); - return new SKRunBuffer (runbuffer, count); + return new SKRawRunBuffer (runbuffer, count, 0, 0); } public SKTextRunBuffer AllocateTextRun (SKFont font, int count, float x, float y, int textByteCount, SKRect? bounds = null) + { + var buffer = AllocateRawTextRun (font, count, x, y, textByteCount, bounds); + return new SKTextRunBuffer (buffer.buffer, count, textByteCount); + } + + public SKRawRunBuffer AllocateRawTextRun (SKFont font, int count, float x, float y, int textByteCount, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -417,12 +416,18 @@ public SKTextRunBuffer AllocateTextRun (SKFont font, int count, float x, float y else SkiaApi.sk_textblob_builder_alloc_run_text (Handle, font.Handle, count, x, y, textByteCount, null, &runbuffer); - return new SKTextRunBuffer (runbuffer, count, textByteCount); + return new SKRawRunBuffer (runbuffer, count, 0, textByteCount); } - // AllocateHorizontalRun + // Allocate*HorizontalRun public SKHorizontalRunBuffer AllocateHorizontalRun (SKFont font, int count, float y, SKRect? bounds = null) + { + var buffer = AllocateRawHorizontalRun (font, count, y, bounds); + return new SKHorizontalRunBuffer (buffer.buffer, count); + } + + public SKRawRunBuffer AllocateRawHorizontalRun (SKFont font, int count, float y, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -433,10 +438,16 @@ public SKHorizontalRunBuffer AllocateHorizontalRun (SKFont font, int count, floa else SkiaApi.sk_textblob_builder_alloc_run_pos_h (Handle, font.Handle, count, y, null, &runbuffer); - return new SKHorizontalRunBuffer (runbuffer, count); + return new SKRawRunBuffer (runbuffer, count, count, 0); } public SKHorizontalTextRunBuffer AllocateHorizontalTextRun (SKFont font, int count, float y, int textByteCount, SKRect? bounds = null) + { + var buffer = AllocateRawHorizontalTextRun (font, count, y, textByteCount, bounds); + return new SKHorizontalTextRunBuffer (buffer.buffer, count, textByteCount); + } + + public SKRawRunBuffer AllocateRawHorizontalTextRun (SKFont font, int count, float y, int textByteCount, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -447,12 +458,19 @@ public SKHorizontalTextRunBuffer AllocateHorizontalTextRun (SKFont font, int cou else SkiaApi.sk_textblob_builder_alloc_run_text_pos_h (Handle, font.Handle, count, y, textByteCount, null, &runbuffer); - return new SKHorizontalTextRunBuffer (runbuffer, count, textByteCount); + return new SKRawRunBuffer (runbuffer, count, count, textByteCount); + } // AllocatePositionedRun public SKPositionedRunBuffer AllocatePositionedRun (SKFont font, int count, SKRect? bounds = null) + { + var buffer = AllocateRawPositionedRun (font, count, bounds); + return new SKPositionedRunBuffer (buffer.buffer, count); + } + + public SKRawRunBuffer AllocateRawPositionedRun (SKFont font, int count, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -463,10 +481,16 @@ public SKPositionedRunBuffer AllocatePositionedRun (SKFont font, int count, SKRe else SkiaApi.sk_textblob_builder_alloc_run_pos (Handle, font.Handle, count, null, &runbuffer); - return new SKPositionedRunBuffer (runbuffer, count); + return new SKRawRunBuffer (runbuffer, count, count, 0); } public SKPositionedTextRunBuffer AllocatePositionedTextRun (SKFont font, int count, int textByteCount, SKRect? bounds = null) + { + var buffer = AllocateRawPositionedTextRun (font, count, textByteCount, bounds); + return new SKPositionedTextRunBuffer (buffer.buffer, count, textByteCount); + } + + public SKRawRunBuffer AllocateRawPositionedTextRun (SKFont font, int count, int textByteCount, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -477,12 +501,18 @@ public SKPositionedTextRunBuffer AllocatePositionedTextRun (SKFont font, int cou else SkiaApi.sk_textblob_builder_alloc_run_text_pos (Handle, font.Handle, count, textByteCount, null, &runbuffer); - return new SKPositionedTextRunBuffer (runbuffer, count, textByteCount); + return new SKRawRunBuffer (runbuffer, count, count, textByteCount); } // AllocateRotationScaleRun public SKRotationScaleRunBuffer AllocateRotationScaleRun (SKFont font, int count, SKRect? bounds = null) + { + var buffer = AllocateRawRotationScaleRun (font, count, bounds); + return new SKRotationScaleRunBuffer (buffer.buffer, count); + } + + public SKRawRunBuffer AllocateRawRotationScaleRun (SKFont font, int count, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -493,10 +523,16 @@ public SKRotationScaleRunBuffer AllocateRotationScaleRun (SKFont font, int count else SkiaApi.sk_textblob_builder_alloc_run_rsxform (Handle, font.Handle, count, null, &runbuffer); - return new SKRotationScaleRunBuffer (runbuffer, count); + return new SKRawRunBuffer (runbuffer, count, count, 0); + } + + public SKRotationScaleTextRunBuffer AllocateRotationScaleTextRun (SKFont font, int count, int textByteCount, SKRect? bounds = null) + { + var buffer = AllocateRawRotationScaleTextRun (font, count, textByteCount, bounds); + return new SKRotationScaleTextRunBuffer (buffer.buffer, count, textByteCount); } - public SKRotationScaleRunBuffer AllocateRotationScaleTextRun (SKFont font, int count, int textByteCount, SKRect? bounds = null) + public SKRawRunBuffer AllocateRawRotationScaleTextRun (SKFont font, int count, int textByteCount, SKRect? bounds = null) { if (font == null) throw new ArgumentNullException (nameof (font)); @@ -507,7 +543,7 @@ public SKRotationScaleRunBuffer AllocateRotationScaleTextRun (SKFont font, int c else SkiaApi.sk_textblob_builder_alloc_run_text_rsxform (Handle, font.Handle, count, textByteCount, null, &runbuffer); - return new SKRotationScaleRunBuffer (runbuffer, count); + return new SKRawRunBuffer (runbuffer, count, count, textByteCount); } } } diff --git a/scripts/azure-pipelines-complete-internal.yml b/scripts/azure-pipelines-complete-internal.yml index af2d7e5068..394a5de69d 100644 --- a/scripts/azure-pipelines-complete-internal.yml +++ b/scripts/azure-pipelines-complete-internal.yml @@ -39,8 +39,12 @@ parameters: name: Azure Pipelines vmImage: ubuntu-20.04 os: linux + - name: enableSigning + displayName: 'Enable package signing (Test signing)' + type: boolean + default: false - name: runCompliance - displayName: 'Run post-build compliance tasks (such as API Scan)' + displayName: 'Run post-build compliance tasks (such as API Scan and PoliCheck)' type: boolean default: false - name: use1ESPipelineTemplates @@ -77,7 +81,27 @@ extends: parameters: buildPipelineType: 'both' buildExternals: ${{ parameters.buildExternals }} - runCompliance: ${{ parameters.runCompliance }} + enableSigning: ${{ parameters.enableSigning }} + ${{ if eq(parameters.runCompliance, 'true') }}: + sdl: + apiscan: + enabled: true + binskim: + break: false + codeInspector: + enabled: true + credscan: + suppressionsFile: $(Build.SourcesDirectory)\scripts\guardian\CredScanSuppressions.json + policheck: + enabled: true + exclusionsFile: $(Build.SourcesDirectory)\scripts\guardian\PoliCheckExclusions.xml + spotBugs: + enabled: false + suppression: + suppressionFile: $(Build.SourcesDirectory)\scripts\guardian\source.gdnsuppress + tsa: + enabled: true + configFile: $(Build.SourcesDirectory)\scripts\guardian\tsaoptions-v2.json use1ESPipelineTemplates: ${{ parameters.use1ESPipelineTemplates }} buildAgentHost: ${{ parameters.buildAgentHost }} buildAgentWindows: ${{ parameters.buildAgentWindows }} diff --git a/scripts/azure-pipelines.yml b/scripts/azure-pipelines.yml index c62f4cb874..30e6bcb5e8 100644 --- a/scripts/azure-pipelines.yml +++ b/scripts/azure-pipelines.yml @@ -46,7 +46,7 @@ parameters: image: 1ESPT-Ubuntu20.04 os: linux - name: runCompliance - displayName: 'Run post-build compliance tasks (such as API Scan)' + displayName: 'Run post-build compliance tasks (such as API Scan and PoliCheck)' type: boolean default: false @@ -76,7 +76,30 @@ extends: parameters: buildPipelineType: 'build' buildExternals: ${{ parameters.buildExternals }} - runCompliance: ${{ parameters.runCompliance }} + ${{ if and(eq(variables['System.TeamProject'], 'devdiv'), ne(variables['System.PullRequest.IsFork'], 'true')) }}: + enableSigning: true + ${{ if or(parameters.runCompliance, and(eq(variables['Build.Reason'], 'Schedule'), or(eq(variables['Build.SourceBranch'], 'refs/heads/main'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')))) }}: + sdl: + apiscan: + enabled: true + binskim: + enabled: true + break: false + codeInspector: + enabled: true + credscan: + enabled: true + # suppressionsFile: $(Build.SourcesDirectory)\scripts\guardian\CredScanSuppressions.json + policheck: + enabled: true + exclusionsFile: $(Build.SourcesDirectory)\scripts\guardian\PoliCheckExclusions.xml + spotBugs: + enabled: false + suppression: + suppressionFile: $(Build.SourcesDirectory)\scripts\guardian\source.gdnsuppress + tsa: + enabled: true + configFile: $(Build.SourcesDirectory)\scripts\guardian\tsaoptions-v2.json use1ESPipelineTemplates: true buildAgentHost: ${{ parameters.buildAgentHost }} buildAgentWindows: ${{ parameters.buildAgentWindows }} diff --git a/scripts/azure-templates-bootstrapper.yml b/scripts/azure-templates-bootstrapper.yml index f476be899c..4e9736538e 100644 --- a/scripts/azure-templates-bootstrapper.yml +++ b/scripts/azure-templates-bootstrapper.yml @@ -35,6 +35,7 @@ parameters: skipInstall: false # whether or not to install any tools skipSteps: false # whether or not to run any steps use1ESPipelineTemplates: false # whether or not we are building using the internal 1ES Pipeline Templates + sdl: [] # the SDL properties to use for this job jobs: - job: ${{ parameters.name }} @@ -49,11 +50,7 @@ jobs: ${{ if ne(length(parameters.variables), 0) }}: ${{ parameters.variables }} templateContext: - sdl: - spotBugs: - enabled: false - binskim: - break: false + sdl: ${{ parameters.sdl }} outputParentDirectory: 'output' outputs: - ${{ if eq(parameters.shouldPublish, 'true') }}: diff --git a/scripts/azure-templates-linux-matrix.yml b/scripts/azure-templates-linux-matrix.yml index 980d3e4be5..26681ce2d0 100644 --- a/scripts/azure-templates-linux-matrix.yml +++ b/scripts/azure-templates-linux-matrix.yml @@ -3,6 +3,7 @@ parameters: buildPipelineType: 'both' # the type of build pipeline setup buildAgent: '' # the configuration for the build agent use1ESPipelineTemplates: false # whether or not we are building using the internal 1ES Pipeline Templates + sdl: [] # the SDL properties to use for this job builds: - name: '' desc: '' @@ -24,6 +25,7 @@ jobs: parameters: name: ${{ replace(replace(format('native_linux_{0}_{1}_{2}_{3}_linux', item.arch, item.variant, build.name, item.alt), '__', '_'), '__', '_') }} displayName: Linux ${{ replace(replace(replace(replace(replace(format('({0}|{1}|{2}|{3})', item.arch, item.variant, build.name, item.alt), '||', '|'), '||', '|'), '(|', '('), '|)', ')'), '|', ', ') }} + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgent }} diff --git a/scripts/azure-templates-merger.yml b/scripts/azure-templates-merger.yml index 0e2858571d..23b9eb65c2 100644 --- a/scripts/azure-templates-merger.yml +++ b/scripts/azure-templates-merger.yml @@ -5,12 +5,14 @@ parameters: buildPipelineType: 'both' # the type of build pipeline setup requiredArtifacts: [] # the artifacts that this build needs to download matrixArtifacts: [] # the artifacts that this build needs to download + sdl: [] # the SDL properties to use for this job jobs: - template: /scripts/azure-templates-bootstrapper.yml@self parameters: name: ${{ parameters.name }} displayName: ${{ parameters.displayName }} + sdl: ${{ parameters.sdl }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgent }} skipInstall: true diff --git a/scripts/azure-templates-stages.yml b/scripts/azure-templates-stages.yml index da6fcea289..b39f34db49 100644 --- a/scripts/azure-templates-stages.yml +++ b/scripts/azure-templates-stages.yml @@ -19,10 +19,19 @@ parameters: type: object - name: buildAgentLinuxNative type: object - - name: runCompliance + - name: sdl + type: object + default: + apiscan: + enabled: false + binskim: + break: false + spotBugs: + enabled: false + - name: use1ESPipelineTemplates type: boolean default: false - - name: use1ESPipelineTemplates + - name: enableSigning type: boolean default: false @@ -56,6 +65,7 @@ stages: parameters: name: native_android_x86_windows displayName: Android x86 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -65,6 +75,7 @@ stages: parameters: name: native_android_x64_windows displayName: Android x64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -74,6 +85,7 @@ stages: parameters: name: native_android_arm_windows displayName: Android arm + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -83,6 +95,7 @@ stages: parameters: name: native_android_arm64_windows displayName: Android arm64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -92,6 +105,7 @@ stages: parameters: name: native_tizen_windows displayName: Tizen + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -100,6 +114,7 @@ stages: parameters: name: native_win32_x86_windows displayName: Win32 x86 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -109,6 +124,7 @@ stages: parameters: name: native_win32_x64_windows displayName: Win32 x64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -118,6 +134,7 @@ stages: parameters: name: native_win32_arm64_windows displayName: Win32 arm64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -127,6 +144,7 @@ stages: parameters: name: native_win32_x86_msvc_windows displayName: Win32 x86 [MSVC] + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -137,6 +155,7 @@ stages: parameters: name: native_win32_x64_msvc_windows displayName: Win32 x64 [MSVC] + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -147,6 +166,7 @@ stages: parameters: name: native_win32_arm64_msvc_windows displayName: Win32 arm64 [MSVC] + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -157,6 +177,7 @@ stages: parameters: name: native_winui_x86_windows displayName: WinUI x86 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -166,6 +187,7 @@ stages: parameters: name: native_winui_x64_windows displayName: WinUI x64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -175,6 +197,7 @@ stages: parameters: name: native_winui_arm64_windows displayName: WinUI arm64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -184,6 +207,7 @@ stages: parameters: name: native_win32_x64_nanoserver_windows displayName: Nano Server x64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindowsNative }} @@ -199,6 +223,7 @@ stages: parameters: name: native_android_x86_macos displayName: Android x86 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -208,6 +233,7 @@ stages: parameters: name: native_android_x64_macos displayName: Android x64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -217,6 +243,7 @@ stages: parameters: name: native_android_arm_macos displayName: Android arm + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -226,6 +253,7 @@ stages: parameters: name: native_android_arm64_macos displayName: Android arm64 + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -235,6 +263,7 @@ stages: parameters: name: native_ios_macos displayName: iOS + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -243,6 +272,7 @@ stages: parameters: name: native_maccatalyst_macos displayName: Mac Catalyst + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -251,6 +281,7 @@ stages: parameters: name: native_macos_macos displayName: macOS + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -259,6 +290,7 @@ stages: parameters: name: native_tvos_macos displayName: tvOS + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -267,6 +299,7 @@ stages: parameters: name: native_tizen_macos displayName: Tizen + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentMacNative }} @@ -279,6 +312,7 @@ stages: jobs: - template: /scripts/azure-templates-linux-matrix.yml@self # Build Native Linux (Linux) parameters: + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentLinuxNative }} @@ -319,6 +353,7 @@ stages: jobs: - template: /scripts/azure-templates-wasm-matrix.yml@self # Build Native WASM (Linux) parameters: + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentLinuxNative }} @@ -391,6 +426,7 @@ stages: parameters: name: native displayName: Merge Native Artifacts + sdl: ${{ parameters.sdl }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentHost }} requiredArtifacts: @@ -428,6 +464,7 @@ stages: parameters: name: native_wasm displayName: Merge Native WASM Artifacts + sdl: ${{ parameters.sdl }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentHost }} matrixArtifacts: @@ -437,6 +474,7 @@ stages: parameters: name: native_msvc displayName: Merge Native MSVC Artifacts + sdl: ${{ parameters.sdl }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentHost }} requiredArtifacts: @@ -502,40 +540,57 @@ stages: parameters: name: package_normal_windows displayName: Package NuGets + sdl: ${{ parameters.sdl }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindows}} target: nuget-normal additionalArgs: --skipExternals="all" + shouldPublish: false requiredArtifacts: - name: native postBuildSteps: - - pwsh: Remove-Item ./output/native/ -Recurse -Force -ErrorAction Continue - displayName: Delete the native folder - pwsh: | - New-Item '$(Build.ArtifactStagingDirectory)\nugets\' -Type Directory -Force | Out-Null - Get-ChildItem '.\output\nugets\' | Copy-Item -Destination '$(Build.ArtifactStagingDirectory)\nugets\' -Recurse -Force - Copy-Item -Path '.\scripts\SignList.xml' -Destination '$(Build.ArtifactStagingDirectory)\nugets\' - Remove-Item '.\output\nugets\' -Recurse -Force - displayName: Move the nugets artifact to the staging directory + Remove-Item ./output/native/ -Recurse -Force -ErrorAction Continue + Move-Item -Path '.\output\' -Destination '$(Build.ArtifactStagingDirectory)\output\' + New-Item '.\output\' -Type Directory -Force | Out-Null + displayName: Re-organize the output folder for publishing + - pwsh: | + Move-Item -Path '$(Build.ArtifactStagingDirectory)\output\nugets\' -Destination '.\output\' + Copy-Item -Path '.\scripts\SignList.xml' -Destination '.\output\nugets\' + displayName: Prepare the nugets artifact for publishing + - pwsh: | + Move-Item -Path '$(Build.ArtifactStagingDirectory)\output\nugets-symbols\' -Destination '.\output\' + displayName: Prepare the nugets-symbols artifact for publishing - pwsh: | - New-Item '$(Build.ArtifactStagingDirectory)\nugets-symbols\' -Type Directory -Force | Out-Null - Get-ChildItem '.\output\nugets-symbols\' | Copy-Item -Destination '$(Build.ArtifactStagingDirectory)\nugets-symbols\' -Recurse -Force - Remove-Item '.\output\nugets-symbols\' -Recurse -Force - displayName: Move the nugets-symbols artifact to the staging directory + Move-Item -Path '$(Build.ArtifactStagingDirectory)\output\' -Destination '.\output\' + displayName: Prepare the build artifact for publishing + - pwsh: | + $nupkgs = (Get-ChildItem ".\output\nugets*\*.*nupkg") + foreach ($nupkg in $nupkgs) { + $filename = $nupkg.Name.TrimEnd('.nupkg') + $dest = ".\output\extracted_nugets\$filename" + Write-Host "Extracting '$nupkg' to '$dest'..." + Expand-Archive $nupkg $dest + } + displayName: Extract all the .nupkg files for scanning publishArtifacts: + - name: package_normal_windows + path: '.\output\output\' - name: nuget - path: '$(Build.ArtifactStagingDirectory)\nugets' + path: '.\output\nugets' - name: nuget_symbols - path: '$(Build.ArtifactStagingDirectory)\nugets-symbols' + path: '.\output\nugets-symbols' - template: /scripts/azure-templates-bootstrapper.yml@self # Package Special NuGets parameters: name: package_special_windows displayName: Package Special NuGets + sdl: ${{ parameters.sdl }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgentWindows}} dependsOn: package_normal_windows target: nuget-special additionalArgs: --skipExternals="all" --exclusive + shouldPublish: false requiredArtifacts: - name: nuget dir: nugets @@ -543,17 +598,22 @@ stages: dir: nugets-symbols postBuildSteps: - pwsh: | - New-Item '$(Build.ArtifactStagingDirectory)\nugets-special\' -Type Directory -Force | Out-Null - Get-ChildItem '.\output\nugets-special\' | Copy-Item -Destination '$(Build.ArtifactStagingDirectory)\nugets-special\' -Recurse -Force - Remove-Item '.\output\nugets-special\' -Recurse -Force - displayName: Move the nugets-special artifact to the staging directory + Remove-Item ./output/nugets/ -Recurse -Force -ErrorAction Continue + Remove-Item ./output/nugets-symbols/ -Recurse -Force -ErrorAction Continue + Move-Item -Path '.\output\' -Destination '$(Build.ArtifactStagingDirectory)\output\' + New-Item '.\output\' -Type Directory -Force | Out-Null + displayName: Re-organize the output folder for publishing - pwsh: | - Remove-Item ./output/nugets/ -Recurse -Force - Remove-Item ./output/nugets-symbols/ -Recurse -Force - displayName: Delete the downloaded artifacts + Move-Item -Path '$(Build.ArtifactStagingDirectory)\output\nugets-special\' -Destination '.\output\' + displayName: Prepare the nugets-special artifact for publishing + - pwsh: | + Move-Item -Path '$(Build.ArtifactStagingDirectory)\output\' -Destination '.\output\' + displayName: Prepare the build artifact for publishing publishArtifacts: + - name: package_special_windows + path: '.\output\output\' - name: nuget_special - path: '$(Build.ArtifactStagingDirectory)\nugets-special' + path: '.\output\nugets-special' - ${{ if ne(parameters.buildPipelineType, 'build') }}: - stage: api_diff @@ -586,7 +646,7 @@ stages: always: true path: '$(Build.SourcesDirectory)\changelogs' - - ${{ if and(eq(variables['System.TeamProject'], 'devdiv'), ne(parameters.buildPipelineType, 'tests'), ne(variables['System.PullRequest.IsFork'], 'true')) }}: + - ${{ if eq(parameters.enableSigning, 'true') }}: - stage: signing displayName: Sign NuGets dependsOn: package @@ -909,33 +969,22 @@ stages: installEmsdk: true initScript: source ~/emsdk/emsdk_env.sh - - ${{ if and(eq(variables['System.TeamProject'], 'devdiv'), ne(parameters.buildPipelineType, 'tests'), ne(variables['System.PullRequest.IsFork'], 'true'), or(and(eq(variables['Build.Reason'], 'Schedule'), or(eq(variables['Build.SourceBranch'], 'refs/heads/main'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'))), parameters.runCompliance)) }}: - - template: security/full/v1.yml@xamarin-templates + - ${{ if eq(parameters.sdl.apiscan.enabled, 'true') }}: + - template: security/apiscan/v0.yml@xamarin-templates parameters: - stageDependsOn: - - package - complianceEnabled: true - complianceTimeoutInMinutes: 480 windowsPoolName: ${{ parameters.buildAgentHost.pool.name }} windowsImageOverride: ${{ parameters.buildAgentHost.pool.image }} + timeoutInMinutes: 480 + stageDependsOn: + - package scanArtifacts: - nuget - nuget_symbols - native_msvc - antiMalwareEnabled: true - binSkimEnabled: false - policheckExclusionFile: $(Build.SourcesDirectory)\scripts\guardian\PoliCheckExclusions.xml - policheckGdnSuppressionFilesFolder: $(Build.SourcesDirectory)\scripts\guardian - credScanEnabled: true - credScanSuppressionFile: $(Build.SourcesDirectory)\scripts\guardian\CredScanSuppressions.json - sourceGdnSuppressionFile: $(Build.SourcesDirectory)\scripts\guardian\source.gdnsuppress - tsaConfigFile: $(Build.SourcesDirectory)\scripts\guardian\tsaoptions-v2.json - tsaReportBranch: $(Build.SourceBranch) - enableCodeInspector: true - apiScanEnabled: true apiScanSoftwareName: 'SkiaSharp' apiScanSoftwareVersionNum: $(SKIASHARP_MAJOR_VERSION) apiScanPreserveLogsFolder: true + apiScanAuthConnectionString: 'runAs=App;AppId=$(ApiScanClientId)' apiScanSurrogateConfigurationFolder: $(Build.ArtifactStagingDirectory)\APIScanSurrogates preScanSteps: - pwsh: | diff --git a/scripts/azure-templates-wasm-matrix.yml b/scripts/azure-templates-wasm-matrix.yml index bbceb72be2..9a383a54b5 100644 --- a/scripts/azure-templates-wasm-matrix.yml +++ b/scripts/azure-templates-wasm-matrix.yml @@ -3,6 +3,7 @@ parameters: buildPipelineType: 'both' # the type of build pipeline setup buildAgent: '' # the configuration for the build agent use1ESPipelineTemplates: false # whether or not we are building using the internal 1ES Pipeline Templates + sdl: [] # the SDL properties to use for this job emscripten: [ ] jobs: @@ -11,6 +12,7 @@ jobs: parameters: name: native_wasm_${{ replace(version.displayName, '.', '_') }}_linux displayName: WASM (${{ version.displayName }}) + sdl: ${{ parameters.sdl }} buildExternals: ${{ parameters.buildExternals }} buildPipelineType: ${{ parameters.buildPipelineType }} buildAgent: ${{ parameters.buildAgent }} diff --git a/scripts/install-openjdk.ps1 b/scripts/install-openjdk.ps1 index 9291f86cb8..3feb68f36f 100644 --- a/scripts/install-openjdk.ps1 +++ b/scripts/install-openjdk.ps1 @@ -6,50 +6,56 @@ Param( $ErrorActionPreference = 'Stop' -Add-Type -AssemblyName System.IO.Compression.FileSystem +if (Test-Path (Join-Path "$env:JAVA_HOME_17_X64" "bin")) { + Write-Host "Java is already installed to '$env:JAVA_HOME_17_X64'..." + $java_home = $env:JAVA_HOME_17_X64 +} else { + Add-Type -AssemblyName System.IO.Compression.FileSystem -$HOME_DIR = if ($env:HOME) { $env:HOME } else { $env:USERPROFILE } + $HOME_DIR = if ($env:HOME) { $env:HOME } else { $env:USERPROFILE } -if ($IsMacOS) { - $ext = "tar.gz" - $url = "https://aka.ms/download-jdk/microsoft-jdk-$Version-macOS-x64.tar.gz" -} elseif ($IsLinux) { - $ext = "tar.gz" - $url = "https://aka.ms/download-jdk/microsoft-jdk-$Version-linux-x64.tar.gz" -} else { - $ext = "zip" - $url = "https://aka.ms/download-jdk/microsoft-jdk-$Version-windows-x64.zip" -} + if ($IsMacOS) { + $ext = "tar.gz" + $url = "https://aka.ms/download-jdk/microsoft-jdk-$Version-macOS-x64.tar.gz" + } elseif ($IsLinux) { + $ext = "tar.gz" + $url = "https://aka.ms/download-jdk/microsoft-jdk-$Version-linux-x64.tar.gz" + } else { + $ext = "zip" + $url = "https://aka.ms/download-jdk/microsoft-jdk-$Version-windows-x64.zip" + } -$jdk = Join-Path "$HOME_DIR" "openjdk" -if ($InstallDestination) { - $jdk = $InstallDestination -} -Write-Host "Install destination is '$jdk'..." + $jdk = Join-Path "$HOME_DIR" "openjdk" + if ($InstallDestination) { + $jdk = $InstallDestination + } + Write-Host "Install destination is '$jdk'..." -$jdkTemp = Join-Path "$HOME_DIR" "openjdk-temp" -$archive = Join-Path "$jdkTemp" "openjdk.$ext" + $jdkTemp = Join-Path "$HOME_DIR" "openjdk-temp" + $archive = Join-Path "$jdkTemp" "openjdk.$ext" -# download -Write-Host "Downloading OpenJDK to '$archive'..." -New-Item -ItemType Directory -Force -Path "$jdkTemp" | Out-Null -(New-Object System.Net.WebClient).DownloadFile("$url", "$archive") + # download + Write-Host "Downloading OpenJDK to '$archive'..." + New-Item -ItemType Directory -Force -Path "$jdkTemp" | Out-Null + (New-Object System.Net.WebClient).DownloadFile("$url", "$archive") -# install -Write-Host "Extracting OpenJDK to '$jdk'..." -New-Item -ItemType Directory -Force -Path "$jdk" | Out-Null -if ($IsMacOS -or $IsLinux) { - tar -vxzf "$archive" -C "$jdk" -} else { - [System.IO.Compression.ZipFile]::ExtractToDirectory("$archive", "$jdk") -} + # install + Write-Host "Extracting OpenJDK to '$jdk'..." + New-Item -ItemType Directory -Force -Path "$jdk" | Out-Null + if ($IsMacOS -or $IsLinux) { + tar -vxzf "$archive" -C "$jdk" + } else { + [System.IO.Compression.ZipFile]::ExtractToDirectory("$archive", "$jdk") + } -# set the JAVA_HOME -if ($IsMacOS) { - $java_home = Join-Path "$jdk" "jdk-$FolderVersion/Contents/Home" -} else { - $java_home = Join-Path "$jdk" "jdk-$FolderVersion" + # set the JAVA_HOME + if ($IsMacOS) { + $java_home = Join-Path "$jdk" "jdk-$FolderVersion/Contents/Home" + } else { + $java_home = Join-Path "$jdk" "jdk-$FolderVersion" + } } + Write-Host "##vso[task.setvariable variable=JAVA_HOME;]$java_home" $env:JAVA_HOME = "$java_home" diff --git a/scripts/install-python.ps1 b/scripts/install-python.ps1 index 029a0869c7..6002b96e5e 100644 --- a/scripts/install-python.ps1 +++ b/scripts/install-python.ps1 @@ -31,12 +31,9 @@ if ($IsMacOS) { } else { $platform = "win32" } - -$downloadUrl = (($pythonManifest - | Where-Object { $_.version -eq $Version } - | Select-Object -First 1).files - | Where-Object { $_.platform -eq $platform -and $_.arch -eq $Arch } - | Select-Object -First 1).download_url +$manifestFileVersion = $pythonManifest | Where-Object { $_.version -eq $Version } | Select-Object -First 1 +$manifestFileItem = $manifestFileVersion.files | Where-Object { $_.platform -eq $platform -and $_.arch -eq $Arch } | Select-Object -First 1 +$downloadUrl = $manifestFileItem.download_url # download $tempDir = Join-Path "$HOME_DIR" "python-temp" diff --git a/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz/CanvasExtensions.cs b/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz/CanvasExtensions.cs index d03462caf8..8b39ae75d9 100644 --- a/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz/CanvasExtensions.cs +++ b/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz/CanvasExtensions.cs @@ -74,11 +74,11 @@ public static void DrawShapedText(this SKCanvas canvas, SKShaper shaper, string // create the text blob using var builder = new SKTextBlobBuilder(); - var run = builder.AllocatePositionedRun(font, result.Codepoints.Length); + var run = builder.AllocateRawPositionedRun(font, result.Codepoints.Length, null); // copy the glyphs - var g = run.GetGlyphSpan(); - var p = run.GetPositionSpan(); + var g = run.Glyphs; + var p = run.Positions; for (var i = 0; i < result.Codepoints.Length; i++) { g[i] = (ushort)result.Codepoints[i]; diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SKGLElement.cs b/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SKGLElement.cs new file mode 100644 index 0000000000..00993eab5d --- /dev/null +++ b/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SKGLElement.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using OpenTK.Graphics; +using System.Windows.Media.Media3D; +using SkiaSharp.Views.Desktop; +using OpenTK.Wpf; +using SkiaSharp; +using OpenTK.Graphics.OpenGL; +using OpenTK.Platform.Windows; +using OpenTK; +using System.Windows.Interop; +using OpenTK.Platform; +#if NETCOREAPP || NET +using OpenTK.Mathematics; +#endif + +namespace SkiaSharp.Views.WPF +{ + [DefaultEvent("PaintSurface")] + [DefaultProperty("Name")] + public class SKGLElement : GLWpfControl, IDisposable + { + private const SKColorType colorType = SKColorType.Rgba8888; + private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.BottomLeft; + + private bool designMode; + + private GRContext grContext; + private GRGlFramebufferInfo glInfo; + private GRBackendRenderTarget renderTarget; + private SKSurface surface; + private SKCanvas canvas; + + private SKSizeI lastSize; + + public SKGLElement() + : base() + { + Initialize(); + } + + private void Initialize() + { + designMode = DesignerProperties.GetIsInDesignMode(this); + var settings = new GLWpfControlSettings() { MajorVersion = 2, MinorVersion = 1, RenderContinuously = false }; + + this.Render += OnPaint; + + this.Loaded += SKGLElement_Loaded; + this.Unloaded += SKGLElement_Unloaded; + +#if NETCOREAPP + this.RegisterToEventsDirectly = false; +#endif + + Start(settings); + } + + private void SKGLElement_Unloaded(object sender, RoutedEventArgs e) + { + Release(); + } + private void SKGLElement_Loaded(object sender, RoutedEventArgs e) + { + InvalidateVisual(); + } + + public SKSize CanvasSize => lastSize; + + public GRContext GRContext => grContext; + + [Category("Appearance")] + public event EventHandler PaintSurface; + + private SKSizeI GetSize() + { + var currentWidth = ActualWidth; + var currentHeight = ActualHeight; + + if (currentWidth < 0 || + currentHeight < 0) + { + currentWidth = 0; + currentHeight = 0; + } + + PresentationSource source = PresentationSource.FromVisual(this); + + double dpiX = 1.0; + double dpiY = 1.0; + if (source != null) + { + dpiX = source.CompositionTarget.TransformToDevice.M11; + dpiY = source.CompositionTarget.TransformToDevice.M22; + } + + return new SKSizeI((int)(currentWidth * dpiX), (int)(currentHeight * dpiY)); + } + + protected override void OnRender(DrawingContext drawingContext) + { + if (grContext != null) + { + grContext.ResetContext(); + } + base.OnRender(drawingContext); + } + + protected virtual void OnPaint(TimeSpan e) + { + if (disposed) + { + return; + } + if (designMode) + { + return; + } + + // create the contexts if not done already + if (grContext == null) + { + var glInterface = GRGlInterface.Create(); + grContext = GRContext.CreateGl(glInterface); + } + + // get the new surface size + var newSize = GetSize(); + + GL.ClearColor(Color4.Transparent); + GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit); + + // manage the drawing surface + if (renderTarget == null || lastSize != newSize || !renderTarget.IsValid) + { + + // create or update the dimensions + lastSize = newSize; + + GL.GetInteger(GetPName.FramebufferBinding, out var framebuffer); + GL.GetInteger(GetPName.StencilBits, out var stencil); + GL.GetInteger(GetPName.Samples, out var samples); + var maxSamples = grContext.GetMaxSurfaceSampleCount(colorType); + if (samples > maxSamples) + samples = maxSamples; + glInfo = new GRGlFramebufferInfo((uint)framebuffer, colorType.ToGlSizedFormat()); + + // destroy the old surface + surface?.Dispose(); + surface = null; + canvas = null; + + // re-create the render target + renderTarget?.Dispose(); + renderTarget = new GRBackendRenderTarget(newSize.Width, newSize.Height, samples, stencil, glInfo); + } + + // create the surface + if (surface == null) + { + surface = SKSurface.Create(grContext, renderTarget, surfaceOrigin, colorType); + canvas = surface.Canvas; + } + + using (new SKAutoCanvasRestore(canvas, true)) + { + // start drawing + OnPaintSurface(new SKPaintGLSurfaceEventArgs(surface, renderTarget, surfaceOrigin, colorType)); + } + + // update the control + canvas.Flush(); + } + + protected virtual void OnPaintSurface(SKPaintGLSurfaceEventArgs e) + { + // invoke the event + PaintSurface?.Invoke(this, e); + } + + private bool disposed = false; + + + protected virtual void Dispose(bool disposing) + { + if (disposed) + { + return; + } + + Release(); + + disposed = true; + } + + private void Release() + { + canvas = null; + surface?.Dispose(); + surface = null; + renderTarget?.Dispose(); + renderTarget = null; + grContext?.Dispose(); + grContext = null; + } + + public void Dispose() + { + Dispose(true); + } + } + +} diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SkiaSharp.Views.WPF.csproj b/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SkiaSharp.Views.WPF.csproj index 8108387533..cc8ba3e40c 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SkiaSharp.Views.WPF.csproj +++ b/source/SkiaSharp.Views/SkiaSharp.Views.WPF/SkiaSharp.Views.WPF.csproj @@ -7,8 +7,17 @@ SkiaSharp.Views.WPF $(DefineConstants);__DESKTOP__;__WPF__ SkiaSharp Views & Layers for Windows Presentation Foundation (WPF) + false wpf + + + + + + + + diff --git a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKMetalView.cs b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKMetalView.cs index f9c1dc97ff..fe0dabc5b9 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKMetalView.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKMetalView.cs @@ -83,6 +83,7 @@ private void Initialize() ColorPixelFormat = MTLPixelFormat.BGRA8Unorm; DepthStencilPixelFormat = MTLPixelFormat.Depth32Float_Stencil8; SampleCount = 1; + FramebufferOnly = false; Device = device; backendContext = new GRMtlBackendContext { diff --git a/tests/Tests/SkiaSharp/SKTextBlobTest.cs b/tests/Tests/SkiaSharp/SKTextBlobTest.cs index 32cb3e35cd..58785b35c7 100644 --- a/tests/Tests/SkiaSharp/SKTextBlobTest.cs +++ b/tests/Tests/SkiaSharp/SKTextBlobTest.cs @@ -16,6 +16,36 @@ public void TestEmptyBuilderReturnsNull() Assert.Null(blob); } + [SkippableFact] + public void RunsAllocateNoPositions() + { + var font = new SKFont(); + + using var builder = new SKTextBlobBuilder(); + + var run = builder.AllocateRun(font, 100, 0, 0); + Assert.Equal(100, run.Glyphs.Length); + + using var blob = builder.Build(); + Assert.NotNull(blob); + } + + [SkippableFact] + public void RawRunsAllocateNoPositions() + { + var font = new SKFont(); + + using var builder = new SKTextBlobBuilder(); + + var run = builder.AllocateRawRun(font, 100, 0, 0); + Assert.Equal(100, run.Glyphs.Length); + Assert.Equal(0, run.Positions.Length); + Assert.Equal(0, run.Text.Length); + + using var blob = builder.Build(); + Assert.NotNull(blob); + } + [SkippableFact] public void TextRunsAllocateTextSpan() { @@ -24,8 +54,23 @@ public void TextRunsAllocateTextSpan() using var builder = new SKTextBlobBuilder(); var run = builder.AllocateTextRun(font, 100, 0, 0, 50); - Assert.Equal(100, run.GetGlyphSpan().Length); - Assert.Equal(50, run.GetTextSpan().Length); + Assert.Equal(100, run.Glyphs.Length); + Assert.Equal(50, run.Text.Length); + + using var blob = builder.Build(); + Assert.NotNull(blob); + } + + [SkippableFact] + public void RawTextRunsAllocateTextSpan() + { + var font = new SKFont(); + + using var builder = new SKTextBlobBuilder(); + + var run = builder.AllocateRawTextRun(font, 100, 0, 0, 50); + Assert.Equal(100, run.Glyphs.Length); + Assert.Equal(50, run.Text.Length); using var blob = builder.Build(); Assert.NotNull(blob); @@ -112,7 +157,7 @@ public unsafe void TestPositionedRunIsBothPointsAndFloats() run.SetPositions(positions); - var span = run.GetPositionSpan(); + var span = run.Positions; Assert.Equal(positions, span.ToArray()); var floats = new float[6];